苍穹外卖java项目笔记 实体类分类
名称
说明
Entity
实体,通常和数据库中的表对应
DTO
数据传输对象,通常用于程序中各层之间传递数据
VO
视图对象,为前端展示数据提供的对象
POJO
普通java对象,只有属性和对应的getter和setter方法
Swagger生成接口文档 使用Swagger只需要按照它的规范定义接口以及接口相关信息,就可以生成接口文档,以及在线接口调试页面。官网:http://swagger.io/
Knife4j是为java MVC框架集成Swagger生成Api文档的增强解决方案
1.导入依赖
1 2 3 4 <dependency > <groupId > com.github.xiaoymin</groupId > <artifactId > knife4j-spring-boot-starter</artifactId > </dependency >
2.在配置类中加入knife4j相关配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @Configuration @Slf4j public class WebMvcConfiguration extends WebMvcConfigurationSupport { @Bean public Docket docket () { log.info("准备生成接口文档……" ); ApiInfo apiInfo = new ApiInfoBuilder () .title("苍穹外卖项目接口文档" ) .version("2.0" ) .description("苍穹外卖项目接口文档" ) .build(); Docket docket = new Docket (DocumentationType.SWAGGER_2) .groupName("管理端接口" ) .apiInfo(apiInfo) .select() .apis(RequestHandlerSelectors.basePackage("com.sky.controller.admin" )) .paths(PathSelectors.any()) .build(); return docket; } }
3.设置静态资源映射,否则接口文档页面无法访问
1 2 3 4 5 6 7 8 9 10 11 protected void addResourceHandlers (ResourceHandlerRegistry registry) { log.info("开始设置静态资源映射……" ); registry.addResourceHandler("/doc.html" ).addResourceLocations("classpath:/META-INF/resources/" ); registry.addResourceHandler("/webjars/**" ).addResourceLocations("classpath:/META-INF/resources/webjars/" ); }
Swagger 常用注解
注解
说明
@Api
用在类上,例如controller,对类进行说明
@ApiModel
同在类上,例如entity,DTO,VO
@ApiModelProperty
用在属性上,描述属性信息
@ApiOperation
用在方法上,例如controller的方法,说明方法的用途、作用
SpringMvc消息转换器 消息转换器配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Configuration @Slf4j public class WebMvcConfiguration extends WebMvcConfigurationSupport { @Override protected void extendMessageConverters (List<HttpMessageConverter<?>> converters) { log.info("扩展消息转换器……" ); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter (); converter.setObjectMapper(new JacksonObjectMapper ()); converters.add(0 , converter); } }
JSON对象转换器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class JacksonObjectMapper extends ObjectMapper { public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd" ; public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm" ; public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss" ; public JacksonObjectMapper () { super (); this .configure(FAIL_ON_UNKNOWN_PROPERTIES, false ); this .getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); SimpleModule simpleModule = new SimpleModule () .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer (DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) .addDeserializer(LocalDate.class, new LocalDateDeserializer (DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))) .addDeserializer(LocalTime.class, new LocalTimeDeserializer (DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))) .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer (DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) .addSerializer(LocalDate.class, new LocalDateSerializer (DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))) .addSerializer(LocalTime.class, new LocalTimeSerializer (DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); this .registerModule(simpleModule); } }
公共字段自动填充(AOP) 实现思路 (技术点:枚举、注解、AOP、反射)
序号
字段名
含义
数据结构
操作类型
1
create_time
创建时间
datetime
insert
2
create_user
创建人id
bigint
insert
3
update_time
修改时间
datetime
insert、update
4
update_user
修改人id
bigint
insert、update
自定义注解AutoFill,标识需要进行公共字段自动填充的方法
自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法,通过反射为公共字段赋值
在Mapper的方法上加入AutoFill注解
自定义注解
1 2 3 4 5 6 7 8 9 10 11 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { OperationType value () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public enum OperationType { UPDATE, INSERT }
切面类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @Aspect @Component @Slf4j public class AutoFillAspect { @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointCut () { } @Before("autoFillPointCut()") public void autoFill (JoinPoint joinPoint) { log.info("开始进行公共字段的自动填充" ); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); OperationType operationType = autoFill.value(); Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0 ) { return ; } Object entity = args[0 ]; LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId(); if (operationType == OperationType.INSERT) { try { Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class); Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class); Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); setCreateTime.invoke(entity, now); setCreateUser.invoke(entity, currentId); setUpdateTime.invoke(entity, now); setUpdateUser.invoke(entity, currentId); } catch (Exception e) { throw new RuntimeException (e); } } else if (operationType == OperationType.UPDATE) { try { Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); setUpdateTime.invoke(entity, now); setUpdateUser.invoke(entity, currentId); } catch (Exception e) { throw new RuntimeException (e); } } } }
mapper上加上注解
1 2 3 4 5 6 7 @AutoFill(value = OperationType.INSERT) void insert (Dish dish) ;
文件上传——阿里云OSS对象存储 依赖
1 2 3 4 5 <dependency > <groupId > com.aliyun.oss</groupId > <artifactId > aliyun-sdk-oss</artifactId > <version > ${aliyun.sdk.oss}</version > </dependency >
配置属性类
1 2 3 4 5 6 7 8 9 10 11 12 @Component @ConfigurationProperties(prefix = "sky.alioss") @Data public class AliOssProperties { private String endpoint; private String accessKeyId; private String accessKeySecret; private String bucketName; }
配置文件
1 2 3 4 5 6 7 sky: alioss: endpoint: ${sky.alioss.endpoint} access-key-id: ${sky.alioss.access-key-id} access-key-secret: ${sky.alioss.access-key-secret} bucket-name: ${sky.alioss.bucket-name}
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 @Data @AllArgsConstructor @Slf4j public class AliOssUtil { private String endpoint; private String accessKeyId; private String accessKeySecret; private String bucketName; public String upload (byte [] bytes, String objectName) { OSS ossClient = new OSSClientBuilder ().build(endpoint, accessKeyId, accessKeySecret); try { ossClient.putObject(bucketName, objectName, new ByteArrayInputStream (bytes)); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason." ); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network." ); System.out.println("Error Message:" + ce.getMessage()); } finally { if (ossClient != null ) { ossClient.shutdown(); } } StringBuilder stringBuilder = new StringBuilder ("https://" ); stringBuilder .append(bucketName) .append("." ) .append(endpoint) .append("/" ) .append(objectName); log.info("文件上传到:{}" , stringBuilder.toString()); return stringBuilder.toString(); } }
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Configuration @Slf4j public class OssConfiguration { @Bean @ConditionalOnMissingBean public AliOssUtil aliOssUtil (AliOssProperties aliOssProperties) { log.info("开始创建阿里晕文件上传工具类对象,{}" ,aliOssProperties); return new AliOssUtil (aliOssProperties.getEndpoint(), aliOssProperties.getAccessKeyId(), aliOssProperties.getAccessKeySecret(), aliOssProperties.getBucketName()); } }
文件上传类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @RestController @RequestMapping("/admin/common") @Api(tags = "通用接口") @Slf4j public class CommonController { @Autowired private AliOssUtil aliOssUtil; @PostMapping("/upload") @ApiOperation("文件上传") public Result<String> upload (MultipartFile file) { log.info("文件上传:{}" , file); try { String originalFilename = file.getOriginalFilename(); String extension = originalFilename.substring(originalFilename.lastIndexOf("." )); String objectName = UUID.randomUUID().toString() + extension; String filePath = aliOssUtil.upload(file.getBytes(), objectName); return Result.success(filePath); } catch (IOException e) { log.error("文件上传失败,{}" , e); } return Result.error(MessageConstant.UPLOAD_FAILED); } }
Jwt权限校验 依赖
1 2 3 4 5 <dependency > <groupId > io.jsonwebtoken</groupId > <artifactId > jjwt</artifactId > <version > ${jjwt}</version > </dependency >
配置属性类
1 2 3 4 5 6 7 8 9 10 11 @Component @ConfigurationProperties(prefix = "sky.jwt") @Data public class JwtProperties { private String adminSecretKey; private long adminTtl; private String adminTokenName;
配置文件
1 2 3 4 5 6 7 8 sky: jwt: admin-secret-key: itcast admin-ttl: 7200000 admin-token-name: token
Jwt工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class JwtUtil { public static String createJWT (String secretKey, long ttlMillis, Map<String, Object> claims) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; long expMillis = System.currentTimeMillis() + ttlMillis; Date exp = new Date (expMillis); JwtBuilder builder = Jwts.builder() .setClaims(claims) .signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8)) .setExpiration(exp); return builder.compact(); } public static Claims parseJWT (String secretKey, String token) { Claims claims = Jwts.parser() .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8)) .parseClaimsJws(token).getBody(); return claims; } }
登录时生成Jwt令牌
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @PostMapping("/login") @ApiOperation(value = "员工登录") public Result<EmployeeLoginVO> login (@RequestBody EmployeeLoginDTO employeeLoginDTO) { log.info("员工登录:{}" , employeeLoginDTO); Employee employee = employeeService.login(employeeLoginDTO); Map<String, Object> claims = new HashMap <>(); claims.put(JwtClaimsConstant.EMP_ID, employee.getId()); String token = JwtUtil.createJWT( jwtProperties.getAdminSecretKey(), jwtProperties.getAdminTtl(), claims); EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder() .id(employee.getId()) .userName(employee.getUsername()) .name(employee.getName()) .token(token) .build(); return Result.success(employeeLoginVO); }
Jwt拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @Component @Slf4j public class JwtTokenAdminInterceptor implements HandlerInterceptor { @Autowired private JwtProperties jwtProperties; public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true ; } String token = request.getHeader(jwtProperties.getAdminTokenName()); try { log.info("jwt校验:{}" , token); Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token); Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString()); log.info("当前员工id:" , empId); BaseContext.setCurrentId(empId); return true ; } catch (Exception ex) { response.setStatus(401 ); return false ; } } }
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Configuration @Slf4j public class WebMvcConfiguration extends WebMvcConfigurationSupport { @Autowired private JwtTokenAdminInterceptor jwtTokenAdminInterceptor; @Autowired private JwtTokenUserInterceptor jwtTokenUserInterceptor; protected void addInterceptors (InterceptorRegistry registry) { log.info("开始注册自定义拦截器..." ); registry.addInterceptor(jwtTokenAdminInterceptor) .addPathPatterns("/admin/**" ) .excludePathPatterns("/admin/employee/login" ); registry.addInterceptor(jwtTokenUserInterceptor) .addPathPatterns("/user/**" ) .excludePathPatterns("/user/user/login" ) .excludePathPatterns("/user/shop/status" ); } }
ThreadLocal 获取全局变量 ThreadLocal 并不是一个Thread,而是一个Thread的局部变量
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问
ThreadLocal 常用方法
public void set(T value) 设置当前线程的线程局部变量的值
返回当前线程所对应的线程局部变量的值
移除当前线程的线程局部变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class BaseContext { public static ThreadLocal<Long> threadLocal = new ThreadLocal <>(); public static void setCurrentId (Long id) { threadLocal.set(id); } public static Long getCurrentId () { return threadLocal.get(); } public static void removeCurrentId () { threadLocal.remove(); } }
Result统一返回结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Data public class Result <T> implements Serializable { private Integer code; private String msg; private T data; public static <T> Result<T> success () { Result<T> result = new Result <T>(); result.code = 1 ; return result; } public static <T> Result<T> success (T object) { Result<T> result = new Result <T>(); result.data = object; result.code = 1 ; return result; } public static <T> Result<T> error (String msg) { Result result = new Result (); result.msg = msg; result.code = 0 ; return result; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 @Data @AllArgsConstructor @NoArgsConstructor public class PageResult implements Serializable { private long total; private List records; }
全局异常处理
定义全局异常处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { @ExceptionHandler public Result exceptionHandler (BaseException ex) { log.error("异常信息:{}" , ex.getMessage()); return Result.error(ex.getMessage()); } @ExceptionHandler public Result exceptionHandler (SQLIntegrityConstraintViolationException ex) { String message = ex.getMessage(); if (message.contains("Duplicate entry" )) { String[] split = message.split(" " ); String username = split[2 ]; String msg = username + MessageConstant.ALREADY_EXISTS; return Result.error(msg); } else { return Result.error(MessageConstant.UNKNOWN_ERROR); } } }
java操作Spring Data Redis
导入依赖
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis</artifactId > </dependency >
配置Redis数据源
1 2 3 4 5 6 7 spring: redis: host: ${sky.redis.host} port: ${sky.redis.port} password: ${sky.redis.password} database: ${sky.redis.database}
编写配置类,创建RedisTemplate对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Configuration @Slf4j public class RedisConfiguration { @Bean public RedisTemplate redisTemplate (RedisConnectionFactory redisConnectionFactory) { log.info("开始创建redis模板对象……" ); RedisTemplate redisTemplate = new RedisTemplate (); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer ()); return redisTemplate; } }
通过RedisTemplate对象操作Redis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class SpringDateRedisTest { @Autowired private RedisTemplate redisTemplate; @Test public void testRedisTemplate () { System.out.println(redisTemplate); ValueOperations valueOperations = redisTemplate.opsForValue(); HashOperations hashOperations = redisTemplate.opsForHash(); ListOperations listOperations = redisTemplate.opsForList(); SetOperations setOperations = redisTemplate.opsForSet(); ZSetOperations zSetOperations = redisTemplate.opsForZSet(); } @Test public void testString () { redisTemplate.opsForValue().set("name" , "北京" ); String city = (String) redisTemplate.opsForValue().get("name" ); System.out.println(city); redisTemplate.opsForValue().set("code" , "1234" , 3 , TimeUnit.MINUTES); redisTemplate.opsForValue().setIfAbsent("lock" , "1" ); redisTemplate.opsForValue().setIfAbsent("lock" , "2" ); } @Test public void testHash () { HashOperations hashOperations = redisTemplate.opsForHash(); hashOperations.put("100" , "name" , "tom" ); hashOperations.put("100" , "age" , "20" ); String name = (String) hashOperations.get("100" , "name" ); System.out.println(name); Set keys = hashOperations.keys("100" ); System.out.println(keys); List values = hashOperations.values("100" ); System.out.println(values); hashOperations.delete("100" , "age" ); } }
Spring Cache Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单加一个注解,就能实现缓存功能
Spring Cache提供了一层抽象,底层可以切换不同的缓存实现,例如:
依赖
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-cache</artifactId > </dependency >
常用注解
注解
说明
@EnableCaching
开启缓存注解功能,通常加载启动类上
@Cacheable
在方法执行前查询缓存中是否有数据,如果有数据则直接返回缓存数据 ,如果没有数据,调用方法并将返回值放到缓存 可取可存
@CachePut
将方法的返回值放在缓存中 只存不取
@CacheEvict
将一条或多条数据从缓存中删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @RestController @RequestMapping("/user") @Slf4j public class UserController { @Autowired private UserMapper userMapper; @PostMapping @CachePut(cacheNames = "userCache", key = "#user.id") public User save (@RequestBody User user) { userMapper.insert(user); return user; } @DeleteMapping @CacheEvict(cacheNames = "userCache", key = "#id") public void deleteById (Long id) { userMapper.deleteById(id); } @DeleteMapping("/delAll") @CacheEvict(cacheNames = "userCache", allEntries = true) public void deleteAll () { userMapper.deleteAll(); } @GetMapping @Cacheable(cacheNames = "userCache", key = "#id") public User getById (Long id) { User user = userMapper.getById(id); return user; } }
HttpClient 依赖(导入阿里云会自动导入该依赖)
1 2 3 4 <dependency > <groupId > org.apache.httpcomponents</groupId > <artifactId > httpclient</artifactId > </dependency >
创建工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 public class HttpClientUtil { static final int TIMEOUT_MSEC = 5 * 1000 ; public static String doGet (String url,Map<String,String> paramMap) { CloseableHttpClient httpClient = HttpClients.createDefault(); String result = "" ; CloseableHttpResponse response = null ; try { URIBuilder builder = new URIBuilder (url); if (paramMap != null ){ for (String key : paramMap.keySet()) { builder.addParameter(key,paramMap.get(key)); } } URI uri = builder.build(); HttpGet httpGet = new HttpGet (uri); response = httpClient.execute(httpGet); if (response.getStatusLine().getStatusCode() == 200 ){ result = EntityUtils.toString(response.getEntity(),"UTF-8" ); } }catch (Exception e){ e.printStackTrace(); }finally { try { response.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } return result; } public static String doPost (String url, Map<String, String> paramMap) throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null ; String resultString = "" ; try { HttpPost httpPost = new HttpPost (url); if (paramMap != null ) { List<NameValuePair> paramList = new ArrayList (); for (Map.Entry<String, String> param : paramMap.entrySet()) { paramList.add(new BasicNameValuePair (param.getKey(), param.getValue())); } UrlEncodedFormEntity entity = new UrlEncodedFormEntity (paramList); httpPost.setEntity(entity); } httpPost.setConfig(builderRequestConfig()); response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "UTF-8" ); } catch (Exception e) { throw e; } finally { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } return resultString; } public static String doPost4Json (String url, Map<String, String> paramMap) throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null ; String resultString = "" ; try { HttpPost httpPost = new HttpPost (url); if (paramMap != null ) { JSONObject jsonObject = new JSONObject (); for (Map.Entry<String, String> param : paramMap.entrySet()) { jsonObject.put(param.getKey(),param.getValue()); } StringEntity entity = new StringEntity (jsonObject.toString(),"utf-8" ); entity.setContentEncoding("utf-8" ); entity.setContentType("application/json" ); httpPost.setEntity(entity); } httpPost.setConfig(builderRequestConfig()); response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "UTF-8" ); } catch (Exception e) { throw e; } finally { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } return resultString; } private static RequestConfig builderRequestConfig () { return RequestConfig.custom() .setConnectTimeout(TIMEOUT_MSEC) .setConnectionRequestTimeout(TIMEOUT_MSEC) .setSocketTimeout(TIMEOUT_MSEC).build(); } }