fwq
2024-09-27 9436a044624dfc8ab027a5345d9814d29a0f74f3
Merge branch 'master-stander' into master-jiayan
173个文件已添加
1个文件已修改
27506 ■■■■■ 已修改文件
hx-redisson/.gitignore 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/pom.xml 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/src/main/java/com/hx/redisson/bean/annotations/RedissonClient.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/src/main/java/com/hx/redisson/config/RedisBeanInit.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/src/main/java/com/hx/redisson/config/RedissonConfig.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/src/main/java/com/hx/redisson/config/RedissonUtil.java 1689 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/src/main/java/com/hx/redisson/entity/RedissondbConfigEntity.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/src/main/java/com/hx/redisson/manager/RedisManager.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/src/main/java/com/hx/redisson/register/RedisRegister.java 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/.gitignore 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/pom.xml 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/AutoDomeUtil.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/GeneratorActionUtil.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/GeneratorDaoUtil.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/GeneratorMapperUtil.java 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/GeneratorServiceUtil.java 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/GeneratorUtil.java 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/common/JdbcType.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/common/Lob.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/common/ReadEntityData.java 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com.hx.auto/common/UrlData.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/GeneratorReadXmlUtil.java 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/file/Action.tpl 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/file/Dao.tpl 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/file/Mapper.tpl 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/file/Service.tpl 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/file/ServiceImpl.tpl 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/StartScanXmlHandler.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/StartScanXmlHandlerImpl.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/util/ConfigUtil.java 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/util/Constants.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/util/CreateMapperUtil.java 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/util/CommonTool.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/java/com/hx/auto/util/GeneratorClassParentUtil.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/resources/ftl/Action.tpl 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/resources/ftl/Dao.tpl 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/resources/ftl/Mapper.tpl 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/resources/ftl/Service.tpl 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_auto/src/main/resources/ftl/ServiceImpl.tpl 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/.gitignore 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/pom.xml 327 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/annotation/Jurisdiction.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/api/CorpMpSpaceApi.java 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/bean/annotations/MysqlAutoAes.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/bean/annotations/RedisClient.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/bean/annotations/RequestSecurity.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/BaseController.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/annotations/MysqlHexAes.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/annotations/repeat/RequestRepeat.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/dao/CommonDao.java 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/dao/mapper/CommonMapper.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/service/CommonService.java 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/service/impl/CommonDaoImpl.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/service/impl/CommonServiceImpl.java 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/common/xml/CommonMapper.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/corp/entity/CorpPayRequest.java 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/corp/entity/CorpPayResponse.java 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/corp/util/WxCorpPayUtil.java 613 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/encryption/PTConstant.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/encryption/PTEncryptionUtil.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/exception/LoginException.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/exception/ParamException.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/exception/ServiceException.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/exception/TipsException.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/CertUtil.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/ClientResponseHandler.java 228 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/CorpMpClientUtil.java 510 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/CorpMpSpaceUtil.java 238 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/CorpMpUtil.java 347 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/CorpWXPayQrUtil.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/HttpClientUtil.java 340 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/HttpUtil.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/HttpXmlUtils.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/MD5Util.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/MPWeixinBaseUtil.java 842 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/MpUtil.java 420 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/RequestHandler.java 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/ResponseHandler.java 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/TenpayHttpClient.java 559 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/TenpayUtil.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/WXPayUtil.java 622 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/WXSignUtils.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/WechatUtil.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/WxMpPayUtil.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mp/util/XMLUtil.java 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/aes/handler/GenericStringHandler.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/aes/springbean/ConstantBean.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/aes/springbean/ExportTableAliasVisitor.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/aes/springbean/FieldData.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/aes/springbean/InitMysqlData.java 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/aes/springbean/MySqlInterceptor.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/aes/springbean/SqlUtils.java 578 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/aes/springbean/VariableAesKey.java 294 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatis/date/handler/GenericDateHandler.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatisTool/SqlSentence.java 251 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/mybatisTool/SqlStringTool.java 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/platform/tool/PlatformSign.java 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/redis/RedisConfig.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/redis/RedisUtil.java 414 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/repeat/check/RequestRepeatUtil.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/resultTool/ResponseCode.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/resultTool/Result.java 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/security/request/RequestRestriction.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/Aes.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/AesUtil.java 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/BarCodeUtil.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/Base64Util.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/BigDecimalUtil.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/BlurDataUtil.java 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/COSUtil.java 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/CVSUtil.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/CheckCodeImageUtil.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/CreateNoTool.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/DateUtil.java 918 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/DownFileUtil.java 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/EmailUtil.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/ExcelFileUtil.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/ExcelUtil.java 1133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/FileConvertTool.java 351 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/FileUtil.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/FileUtils.java 666 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/GsonUtils.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/HttpMethodUtil.java 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/HttpResponse.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/HttpServletRequestUtil.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/HttpUtil.java 658 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/IPUtils.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/ImageBase64Util.java 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/ImagesAddDomain.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/JwtConstant.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/JwtTool.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/MD5.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/MD5Util.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/MapUtil.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/MultipartFileUtil.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/MyRedisTemplate.java 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/NumberUtil.java 418 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/OBSUtil.java 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/OSSUtil.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/QRCodeUtil.java 278 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/RegValidatorUtil.java 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/RequestMethod.java 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/SerializeUtil.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/SimpleEncrypt.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/SimpleTool.java 1097 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/StreamUtils.java 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/StringUtils.java 372 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/TempltUtil.java 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/TengXunMapUtil.java 191 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/ThreadPoolUtils.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/WebUtil.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/XmlUtil.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/code/NumberTool.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/corp/CorpMpUtil.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/corp/entity/AppLetInfo.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/corp/entity/OpenIdAUserId.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/corp/entity/WeiXinInfo.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/gaode/AddressCode.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/gaode/GaoDeMapUtil.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/mysql/aes/MysqlHexAesTool.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/rsa/Base64.java 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/rsa/RSASignature.java 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/rsa/RSAUtil.java 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/util/thread/ExecutorServiceTool.java 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hx/wx/gzh/WxGzhUtil.java 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hz/util/http/HttpHzUtil.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/hz/util/http/dto/HttpHzResponse.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/qq/weixin/mp/aes/AesException.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/qq/weixin/mp/aes/ByteGroup.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/qq/weixin/mp/aes/PKCS7Encoder.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/qq/weixin/mp/aes/SHA1.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/qq/weixin/mp/aes/WXBizMsgCrypt.java 296 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx_common/src/main/java/com/qq/weixin/mp/aes/XMLParse.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hx-redisson/.gitignore
New file
@@ -0,0 +1,25 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/target
/.idea
hx-redisson/pom.xml
New file
@@ -0,0 +1,71 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.hx.gitee</groupId>
        <artifactId>hx-parent</artifactId>
        <version>stander</version>
    </parent>
    <artifactId>hx-redisson</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
        </dependency>
        <dependency>
            <groupId>com.dtflys.forest</groupId>
            <artifactId>spring-boot-starter-forest</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>hx-redisson</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                    <include>**/*.tld</include>
                    <include>**/*.tpl</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>profile-active/**</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>${runtime.env}</directory>
            </resource>
        </resources>
    </build>
</project>
hx-redisson/src/main/java/com/hx/redisson/bean/annotations/RedissonClient.java
New file
@@ -0,0 +1,24 @@
package com.hx.redisson.bean.annotations;
import com.hx.redisson.config.RedisBeanInit;
import com.hx.redisson.config.RedissonConfig;
import com.hx.redisson.config.RedissonUtil;
import com.hx.redisson.register.RedisRegister;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**使用redis链接
 *这里的Import的两个类就是需要加载的bean,这样就可以通过简单的添加一个注解来加载自己自定义的bean了,而且可
 *以是很多个,可以打到jar包里面通过Maven引入都是ok的;
 * @author CJH
 * @date 202-06-17
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({RedisBeanInit.class,RedisRegister.class, RedissonUtil.class, RedissonConfig.class})
public @interface RedissonClient {
}
hx-redisson/src/main/java/com/hx/redisson/config/RedisBeanInit.java
New file
@@ -0,0 +1,92 @@
package com.hx.redisson.config;
import com.hx.redisson.entity.RedissondbConfigEntity;
import com.hx.redisson.manager.RedisManager;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * RedisTemplate 初始化类
 *
 * @author CJH
 * @date 2020年12月16日22:38:46
 */
/**要在RedisAutoConfiguration 自动配置前执行*/
@AutoConfigureBefore({RedisAutoConfiguration.class})
/**实现 EnvironmentAware 用于获取全局环境
实现 ApplicationContextAware 用于获取Spring Context 上下文*/
public class RedisBeanInit implements EnvironmentAware, ApplicationContextAware {
    private Logger logger = LoggerFactory.getLogger(RedisBeanInit.class);
     /**用于获取环境配置*/
    private Environment environment;
    /**用于绑定对象*/
    private Binder binder;
    /**Spring context*/
    private ApplicationContext applicationContext;
    /**线程安全的hashmap*/
    private Map<String, RedisTemplate> redisTemplateMap = new ConcurrentHashMap<>();
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    /**
     * 设置环境
     *
     * @param environment
     */
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        this.binder = Binder.get(environment);
    }
    @PostConstruct // Constructor >> @Autowired >> @PostConstruct 用于执行一个 非静态的void 方法,常应用于初始化资源
    public void initAllRedisTemlate() {
        logger.info("<<<初始化系统的RedisTemlate开始>>>");
        RedissondbConfigEntity redissondb;
        try {
            redissondb = binder.bind("redissondb", RedissondbConfigEntity.class).get();
        } catch (Exception e) {
            logger.error("读取redissondb环境配置失败", e);
            return;
        }
        List<Integer> databases = redissondb.getDatabases();
        if (CollectionUtils.isNotEmpty(databases)) {
            databases.forEach(db -> {
                Object bean = applicationContext.getBean("redisTemplate" + db);
                if (bean != null && bean instanceof RedisTemplate) {
                    redisTemplateMap.put("redisTemplate" + db, (RedisTemplate) bean);
                } else {
                    throw new RuntimeException("初始化RedisTemplate" + db + "失败,请检查配置");
                }
            });
        }
        logger.info("已经装配的redistempleate,map:{}", redisTemplateMap);
        logger.info("<<<初始化系统的RedisTemlate完毕>>>");
    }
    @Bean
    public RedisManager getRedisManager() {
        return new RedisManager(redisTemplateMap);
    }
}
hx-redisson/src/main/java/com/hx/redisson/config/RedissonConfig.java
New file
@@ -0,0 +1,36 @@
package com.hx.redisson.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
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.StringRedisSerializer;
/**配置实例化
 * CJH
 */
@Configuration
public class RedissonConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}
hx-redisson/src/main/java/com/hx/redisson/config/RedissonUtil.java
New file
@@ -0,0 +1,1689 @@
package com.hx.redisson.config;
import com.hx.redisson.manager.RedisManager;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
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.data.redis.core.ZSetOperations;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
 * <h1>RedisUtil 操作工具类</h1>
 * @author CJH
 */
public class RedissonUtil {
    private Logger logger = LoggerFactory.getLogger(RedissonUtil.class);
    @Autowired
    private RedisManager redisManager;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 指定缓存失效时间
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time < 0) {
                throw new RuntimeException("设置时间不能为负数:"+time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time,int db) {
        try {
            if (time < 0) {
                throw new RuntimeException("设置时间不能为负数:"+time);
            }
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.expire(key, time, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 指定缓存失效时间
     *
     * @param key      键
     * @param time     时间
     * @param timeUnit 时间类型
     * @return
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        try {
            if (time < 0) {
                throw new RuntimeException("设置时间不能为负数:"+time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 指定缓存失效时间
     *
     * @param key      键
     * @param time     时间
     * @param timeUnit 时间类型
     * @return
     */
    public boolean expire(String key, long time, TimeUnit timeUnit,int db) {
        try {
            if (time < 0) {
                throw new RuntimeException("设置时间不能为负数:"+time);
            }
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.expire(key, time, timeUnit);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key,int db) {
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }
    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(int db,String... key) {
        if (key != null && key.length > 0) {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }
    // ============================String=============================
    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key,int db) {
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time,int db) {
        try {
            if (time > 0) {
                RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value,db);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 普通缓存放入并设置时间,并增加时间类型选择
     *
     * @param key      键
     * @param value    值
     * @param time     时间 time要大于0 如果time小于等于0 将设置无限期
     * @param timeUnit 时间类型
     * @return
     */
    public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, timeUnit);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 普通缓存放入并设置时间,并增加时间类型选择
     *
     * @param key      键
     * @param value    值
     * @param time     时间 time要大于0 如果time小于等于0 将设置无限期
     * @param timeUnit 时间类型
     * @return
     */
    public boolean set(String key, Object value, long time, TimeUnit timeUnit,int db) {
        try {
            if (time > 0) {
                RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
                redisTemplate.opsForValue().set(key, value, time, timeUnit);
            } else {
                set(key, value,db);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }
    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta,int db) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return redisTemplate.opsForValue().increment(key, delta);
    }
    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }
    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta,int db) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return redisTemplate.opsForValue().increment(key, -delta);
    }
    /**如果值存在就不存入,如果不存在就存入
     * @param key     键
     * @param value   值
     * @param timeOut 时间
     * @param unit    时间单位
     */
    public Boolean setIfAbsent(String key, Object value, long timeOut, TimeUnit unit) {
        try {
            return redisTemplate.opsForValue().setIfAbsent(key, value, timeOut, unit);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**如果值存在就不存入,如果不存在就存入
     * @param key     键
     * @param value   值
     * @param timeOut 时间
     * @param unit    时间单位
     */
    public Boolean setIfAbsent(String key, Object value, long timeOut, TimeUnit unit,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForValue().setIfAbsent(key, value, timeOut, unit);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    // ================================Map=================================
    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }
    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item,int db) {
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return redisTemplate.opsForHash().get(key, item);
    }
    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }
    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key,int db) {
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return redisTemplate.opsForHash().entries(key);
    }
    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time,db);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time,db);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }
    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(int db,String key, Object... item) {
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        redisTemplate.opsForHash().delete(key, item);
    }
    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }
    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item,int db) {
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return redisTemplate.opsForHash().hasKey(key, item);
    }
    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }
    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by,int db) {
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return redisTemplate.opsForHash().increment(key, item, by);
    }
    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }
    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by,int db) {
        RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
        return redisTemplate.opsForHash().increment(key, item, -by);
    }
    // ============================set=============================
    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 根据key获取Set中的指定几个随机内容
     *
     * @param key  键
     * @param size 个数
     * @return
     */
    public List sRandomGet(String key, Integer size) {
        try {
            return redisTemplate.opsForSet().randomMembers(key, size);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 根据key获取Set中的指定几个随机内容
     *
     * @param key  键
     * @param size 个数
     * @return
     */
    public List sRandomGet(String key, Integer size,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForSet().randomMembers(key, size);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(int db,String key, Object... values) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(int db,String key, long time, Object... values) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time,db);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(int db,String key, Object... values) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    // ===============================list=================================
    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time,db);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSetAll(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSetAll(String key, List<Object> value,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSetAll(String key, List<Object> value, long time) {
        try {
            // 设置超时时间 原子化
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSetAll(String key, List<Object> value, long time,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            // 设置超时时间 原子化
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time,db);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 根据给定的布隆过滤器添加值
     *
     * @param bloomFilterHelper bloom布隆过滤器解析类
     * @param key               redis 的key
     * @param value             redis 的value
     * @param <T>               值的类型
     */
    /*public <T> void addByBloomFilter(BloomFilterHelper<T> bloomFilterHelper, String key, T value) {
        Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
        int[] offset = bloomFilterHelper.murmurHashOffset(value);
        for (int i : offset) {
            redisTemplate.opsForValue().setBit(key, i, true);
        }
    }*/
    /**
     * 根据给定的布隆过滤器判断值是否存在
     *
     * @param bloomFilterHelper bloom布隆过滤器解析类
     * @param key               redis 的key
     * @param value             redis 的value
     * @param <T>               值的类型
     * @return 存在 true
     */
   /* public <T> boolean includeByBloomFilter(BloomFilterHelper<T> bloomFilterHelper, String key, T value) {
        Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
        int[] offset = bloomFilterHelper.murmurHashOffset(value);
        for (int i : offset) {
            if (!redisTemplate.opsForValue().getBit(key, i)) {
                return false;
            }
        }
        return true;
    }*/
    /**
     * zset 添加元素
     *
     * @param key
     * @param time
     * @param tuples
     * @return
     */
    public long zsSetAndTime(String key, long time, Set<ZSetOperations.TypedTuple<Object>> tuples) {
        try {
            Long count = redisTemplate.opsForZSet().add(key, tuples);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * zset 添加元素
     *
     * @param key
     * @param time
     * @param tuples
     * @return
     */
    public long zsSetAndTime(String key, long time, Set<ZSetOperations.TypedTuple<Object>> tuples,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            Long count = redisTemplate.opsForZSet().add(key, tuples);
            if (time > 0) {
                expire(key, time,db);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * zset 添加元素
     *
     * @param key
     * @param tuples
     * @return
     */
    public long zsSet(String key, Set<ZSetOperations.TypedTuple<Object>> tuples) {
        try {
            Long count = redisTemplate.opsForZSet().add(key, tuples);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * zset 添加元素
     *
     * @param key
     * @param tuples
     * @return
     */
    public long zsSet(String key, Set<ZSetOperations.TypedTuple<Object>> tuples,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            Long count = redisTemplate.opsForZSet().add(key, tuples);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * zs 移除元素
     *
     * @param key
     * @param values
     * @return
     */
    public long zsRemove(String key, Object... values) {
        try {
            Long remove = redisTemplate.opsForZSet().remove(key, values);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * zs 移除元素
     *
     * @param key
     * @param values
     * @return
     */
    public long zsRemove(int db,String key, Object... values) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            Long remove = redisTemplate.opsForZSet().remove(key, values);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列
     *
     * @param key   键
     * @param start 起始位置 0
     * @param end   末尾位置 -1
     * @return 0 -1 返回按分数递增的顺序集合  仅返回 key
     */
    public Set zsGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列
     *
     * @param key   键
     * @param start 起始位置 0
     * @param end   末尾位置 -1
     * @return 0 -1 返回按分数递增的顺序集合  仅返回 key
     */
    public Set zsGet(String key, long start, long end,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForZSet().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列
     *
     * @param key   键
     * @param start 起始位置 0
     * @param end   末尾位置 -1
     * @return 0 -1 返回按分数递增的顺序集合,返回成员对象
     */
    public Set zsGetWithScores(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列
     *
     * @param key   键
     * @param start 起始位置 0
     * @param end   末尾位置 -1
     * @return 0 -1 返回按分数递增的顺序集合,返回成员对象
     */
    public Set zsGetWithScores(String key, long start, long end,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递减(从大到小)顺序排列
     *
     * @param key   键
     * @param start 起始位置 0
     * @param end   末尾位置 -1
     * @return 0 -1 返回按分数递增的顺序集合  仅返回 key
     */
    public Set zsGetReverse(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().reverseRange(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递减(从大到小)顺序排列
     *
     * @param key   键
     * @param start 起始位置 0
     * @param end   末尾位置 -1
     * @return 0 -1 返回按分数递增的顺序集合  仅返回 key
     */
    public Set zsGetReverse(String key, long start, long end,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForZSet().reverseRange(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 通过索引区间返回有序集合成指定区间内的成员对象,其中有序集成员按分数值递减(从大到小)顺序排列
     *
     * @param key   键
     * @param start 起始位置 0
     * @param end   末尾位置 -1
     * @return 0 -1 返回按分数递增的顺序集合,返回成员对象
     */
    public Set zsGetReverseWithScores(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 通过索引区间返回有序集合成指定区间内的成员对象,其中有序集成员按分数值递减(从大到小)顺序排列
     *
     * @param key   键
     * @param start 起始位置 0
     * @param end   末尾位置 -1
     * @return 0 -1 返回按分数递增的顺序集合,返回成员对象
     */
    public Set zsGetReverseWithScores(String key, long start, long end,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 原子加
     * @param key 键
     * @param num 数量
     */
    public Long increment(String key,long num) {
        try {
            return redisTemplate.opsForValue().increment(key, num);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 原子加
     * @param key 键
     * @param num 数量
     * @param db 数据库
     */
    public Long increment(String key,long num,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForValue().increment(key, num);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 原子减
     * @param key 键
     * @param num 数量
     */
    public Long decrement(String key,long num) {
        try {
            return redisTemplate.opsForValue().decrement(key, num);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 原子减
     * @param key 键
     * @param num 数量
     * @param db 数据库
     */
    public Long decrement(String key,long num,int db) {
        try {
            RedisTemplate redisTemplate = redisManager.getRedisTemplate(db);
            return redisTemplate.opsForValue().decrement(key, num);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 获取红锁
     * @param key  锁key
     * @param db 数据库编号
     */
    public RLock getRLock(String key,int db) {
        RLock lock = null;
        try {
            RedissonClient redissonClient = RedisManager.redissonTemplateMap.get(db+"");
            lock = redissonClient.getLock(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return lock;
    }
}
hx-redisson/src/main/java/com/hx/redisson/entity/RedissondbConfigEntity.java
New file
@@ -0,0 +1,30 @@
package com.hx.redisson.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
 * redisconfig 配置实体类
 *
 * @author CJH
 * @date 2022-06-27
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RedissondbConfigEntity implements Serializable {
    /**地址*/
    private String host;
    /**端口*/
    private String port;
    /**密码*/
    private String password;
    /**所有的db序号*/
    private List<Integer> databases = new ArrayList<>();
}
hx-redisson/src/main/java/com/hx/redisson/manager/RedisManager.java
New file
@@ -0,0 +1,46 @@
package com.hx.redisson.manager;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * redis管理
 *
 * @author CJH
 * @date  2022-06-27
 */
public class RedisManager {
    private Map<String, RedisTemplate> redisTemplateMap = new ConcurrentHashMap<>();
    public static Map<String, RedissonClient> redissonTemplateMap = new ConcurrentHashMap<>();
    /**
     * 构造方法初始化 redisTemplateMap 的数据
     *
     * @param redisTemplateMap
     */
    public RedisManager(Map<String, RedisTemplate> redisTemplateMap) {
        this.redisTemplateMap = redisTemplateMap;
    }
    /**
     * 根据数据库序号,返回对应的RedisTemplate
     *
     * @param dbIndex 序号
     * @return {@link RedisTemplate}
     */
    public RedisTemplate getRedisTemplate(Integer dbIndex) {
        RedisTemplate redisTemplate = redisTemplateMap.get("redisTemplate" + dbIndex);
        if (redisTemplate == null) {
            throw new RuntimeException("Map不存在该redisTemplate");
        }
        return redisTemplate;
    }
}
hx-redisson/src/main/java/com/hx/redisson/register/RedisRegister.java
New file
@@ -0,0 +1,145 @@
package com.hx.redisson.register;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.hx.redisson.entity.RedissondbConfigEntity;
import com.hx.redisson.manager.RedisManager;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.redisson.spring.data.connection.RedissonConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
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 java.util.List;
/**
 * <h1>redistemplate初始化</h1>
 * <p>
 * 作用:
 * <p>
 * 读取系统配置,系统启动时,读取redis 的配置,初始化所有的redistemplate
 * 并动态注册为bean
 *
 * @author gengzi
 * @date 2021年1月5日22:16:29
 */
@Configuration
public class RedisRegister implements EnvironmentAware, ImportBeanDefinitionRegistrar {
    private Logger logger = LoggerFactory.getLogger(RedisRegister.class);
    /**用于获取环境配置*/
    private Environment environment;
    /**用于绑定对象*/
    private Binder binder;
    /**
     * 设置环境
     *
     * @param environment
     */
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        this.binder = Binder.get(environment);
    }
    /**
     * 注册bean
     *
     * @param importingClassMetadata
     * @param registry
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        logger.info("《《《动态注册bean开始》》》");
        RedissondbConfigEntity redissondb;
        try {
            redissondb = binder.bind("redissondb", RedissondbConfigEntity.class).get();
        } catch (Exception e) {
            logger.error("读取redissondb环境配置失败", e);
            return;
        }
        List<Integer> databases = redissondb.getDatabases();
        if (CollectionUtils.isNotEmpty(databases)) {
            databases.forEach(db -> {
                // 单机模式,集群只能使用db0
                Config config = new Config();
                config.setCodec(StringCodec.INSTANCE);
                SingleServerConfig singleConfig = config.useSingleServer();
                singleConfig.setAddress("redis://"+redissondb.getHost()+":"+redissondb.getPort());
                singleConfig.setPassword(redissondb.getPassword());
                singleConfig.setDatabase(db);
                System.out.println("getHost:"+singleConfig.getAddress());
                System.out.println("getHost:"+singleConfig.getPassword());
                RedissonClient redissonClient = Redisson.create(config);
                // 构造RedissonConnectionFactory
                RedissonConnectionFactory redisConnectionFactory = new RedissonConnectionFactory(redissonClient);
                // bean定义
                GenericBeanDefinition redisTemplate = new GenericBeanDefinition();
                // 设置bean 的类型
                redisTemplate.setBeanClass(RedisTemplate.class);
                // 设置自动注入的形式,根据名称
                redisTemplate.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
                // redisTemplate 的属性配置
                redisTemplate(redisTemplate, redisConnectionFactory);
                // 注册Bean
                registry.registerBeanDefinition("redisTemplate" + db, redisTemplate);
                RedisManager.redissonTemplateMap.put(db+"",redissonClient);
            });
        }
        logger.info("《《《动态注册bean结束》》》");
    }
    /**
     * redisTemplate 的属性配置
     *
     * @param redisTemplate          泛型bean
     * @param redisConnectionFactory 连接工厂
     * @return
     */
    public GenericBeanDefinition redisTemplate(GenericBeanDefinition redisTemplate, RedisConnectionFactory redisConnectionFactory) {
        RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // key采用String的序列化方式,value采用json序列化方式
        // 通过方法设置属性值
        redisTemplate.getPropertyValues().add("connectionFactory", redisConnectionFactory);
        redisTemplate.getPropertyValues().add("keySerializer", stringRedisSerializer);
        redisTemplate.getPropertyValues().add("hashKeySerializer", stringRedisSerializer);
        redisTemplate.getPropertyValues().add("valueSerializer", jackson2JsonRedisSerializer);
        redisTemplate.getPropertyValues().add("hashValueSerializer", jackson2JsonRedisSerializer);
        return redisTemplate;
    }
}
hx_auto/.gitignore
New file
@@ -0,0 +1,26 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
*.iml
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/target/
/.idea
hx_auto/pom.xml
New file
@@ -0,0 +1,90 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.hx.gitee</groupId>
    <artifactId>hx-auto</artifactId>
    <version>stander</version>
    <properties>
        <!--模板-->
        <freemarker.version>2.3.28</freemarker.version>
        <!--mybatis自动生成-->
        <mybatis.actable>1.1.1.RELEASE</mybatis.actable>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>${freemarker.version}</version>
        </dependency>
        <!-- 数据库自动生成表 -->
        <dependency>
            <groupId>com.gitee.sunchenbin.mybatis.actable</groupId>
            <artifactId>mybatis-enhance-actable</artifactId>
            <version>${mybatis.actable}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.5.RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                    <include>**/*.tld</include>
                    <include>**/*.tpl</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                    <include>**/*.tld</include>
                    <include>**/*.tpl</include>
                </includes>
            </resource>
            <resource>
                <directory>${runtime.env}</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
hx_auto/src/main/java/com.hx.auto/AutoDomeUtil.java
New file
@@ -0,0 +1,53 @@
package com.hx.auto;
import com.hx.auto.common.UrlData;
import java.util.Map;
/**
 * 自动生成工具
 * 2019-08-29
 * @author cjh
 *
 */
public class AutoDomeUtil {
    public static void main(String[] args) throws Exception {
        System.out.println("开始");
        UrlData urlData = new UrlData();
        urlData.setTotalUrl("com.hx");
        urlData.actionUrlData("hx-web.src.main.java","com.hx.controller.admin");
        urlData.daoUrlData("hx-web.src.main.java","com.hx.dao.mapper");
        urlData.serviceUrlData("hx-web.src.main.java","com.hx.service");
        urlData.serviceImplUrlData("hx-web.src.main.java","com.hx.service.impl");
        urlData.mapperUrlData("hx-web.src.main.java", "com.hx.dao.mapperXml");
    /*
        //dao
        GeneratorUtil.generatorDao(SysAdmin.class,urlData);
        //mapper
        GeneratorUtil.generatorMapper(SysAdmin.class, urlData);
        //action
        GeneratorUtil.generatorAction(SysAdmin.class,urlData);
        // 生成service
        GeneratorUtil.generatorService(SysAdmin.class,urlData);
        //通过实体类的包获取所有的表,直接全部生成
        //GeneratorUtil.generatorTableByPackUrl("com.hx.model", urlData);
        */
        //generatorTableByPackUrl(packPath, urlData);
        /*Class cl = TestM2.class;
        Field[] fields = cl.getDeclaredFields();
        for(Field field:fields) {
            System.out.println("field.getName():"+field.getName());
            System.out.println("field.getType():"+field.getType());
            System.out.println("field.getGenericType():"+field.getGenericType());
            System.out.println("field.getModifiers():"+field.getModifiers());
        }*/
        //StringBuffer stringBuffer = SimpleToolUtil.getFileContent("com/cjh/auto/file/test.txt");
        //System.out.println("stringBuffer:"+stringBuffer);
    }
}
hx_auto/src/main/java/com.hx.auto/GeneratorActionUtil.java
New file
@@ -0,0 +1,114 @@
package com.hx.auto;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import com.hx.auto.common.UrlData;
import com.hx.auto.util.CommonTool;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
/**
 * 自动生成action
 *
 * @author chenjiahe 2019年09月08日16:57:47
 *
 */
public class GeneratorActionUtil {
    private static String templateDir = "/ftl";//获取模板路径
    private static String templateName = "Action.tpl";//action模板名称
    /**生成action
     * @param cl 实体类
     * @param urlData 生成配置信息
     * @param sqlParam 是否生成动态sql的文件(sqlSentence.java),已经生成就不用生成
     * @throws Exception
     */
    public static void generatorAction(Class<?> cl, UrlData urlData, boolean sqlParam) throws Exception {
        try {
            // 反射start
            // 类名
            String entityName = cl.getSimpleName();
            // 类名首字母小写
            String initial = entityName.substring(0, 1).toLowerCase();
            String entityNameSmall = initial + entityName.substring(1, entityName.length());
            //判断是否存在
            //生成文件路径
            String targetFile = urlData.getActionUrl()[1].replace(".", "/")+"/";
            //生成文件名称
            targetFile += entityName + "Controller.java";
            targetFile = "./"+urlData.getActionUrl()[0].replace(".", "/")+"/"+targetFile;
            File file = new File(targetFile);
            if(file.exists()){
                //存在就结束
                return;
            }
            //获取实体类包名
            String[] strs = cl.getName().split("\\.");
            String packageName = "";
            //去掉类名
            for(int i=0;i<strs.length-1;i++) {
                packageName += "."+strs[i];
            }
            packageName = packageName.replaceFirst(".", "");
            //获取模板
            Configuration configuration = new Configuration(Configuration.getVersion());
            configuration.setClassForTemplateLoading(GeneratorActionUtil.class, templateDir);
            //configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "填你的resource下的路径,比如/ftl"));
            Template template = configuration.getTemplate(templateName);
            // 创建数据模型
            HashMap<String, Object> root = new HashMap<String, Object>();
            //action包名
            if(!CommonTool.checkNotNull(urlData.getActionUrl())) {
                System.err.println("没有生成action路径");
                return;
            }
            root.put("packageName",urlData.getActionUrl()[1]);
            //实体类的类名
            root.put("entityName", entityName);
            //实体类的类名(首字母小写)
            root.put("entityNameSmall", entityNameSmall);
            if(!CommonTool.checkNotNull(urlData.getTotalUrl())) {
                System.err.println("没有设置总包路径");
                return;
            }
            //dao的包名
            if(!CommonTool.checkNotNull(urlData.getDaoUrl())) {
                System.err.println("没有dao路径");
                return;
            }
            root.put("TotalPackageName",urlData.getTotalUrl());
            root.put("DAOPackageName",urlData.getDaoUrl()[1]);
            //实体类的包名
            root.put("entityPackageName",packageName);
            //service的包名
            if(!CommonTool.checkNotNull(urlData.getServiceUrl())) {
                System.err.println("没有service路径");
                return;
            }
            root.put("servicePackageName",urlData.getServiceUrl()[1]);
            // 将模板和数据模型合并 输出到Console
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile), "UTF-8"));
            template.process(root, out);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
hx_auto/src/main/java/com.hx.auto/GeneratorDaoUtil.java
New file
@@ -0,0 +1,110 @@
package com.hx.auto;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import com.hx.auto.common.UrlData;
import com.hx.auto.util.CommonTool;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
/**
 * 自动生成DAO
 * @author chenjiahe 2019年09月08日16:57:47
 *
 */
public class GeneratorDaoUtil {
    private static String templateDir = "/ftl";//获取模板路径
    private static String templateName = "Dao.tpl";//action模板名称
    /**生成Dao
     * @param cl 实体类
     * @param urlData 生成配置信息
     * @throws Exception
     */
    public static void generatorDao(Class<?> cl,UrlData urlData) throws Exception {
        try {
            // 反射start
            // 类名
            String entityName = cl.getSimpleName();
            // 类名首字母小写
            String initial = entityName.substring(0, 1).toLowerCase();
            String entityNameSmall = initial + entityName.substring(1, entityName.length());
            //生成文件路径
            String targetFile = urlData.getDaoUrl()[1].replace(".", "/")+"/";
            //生成文件名称
            targetFile += entityName + "Mapper.java";
            //映射文件的文件夹
            //补全路径
            targetFile = "./"+urlData.getDaoUrl()[0].replace(".", "/")+"/"+targetFile;
            File file = new File(targetFile);
            if(file.exists()){
                //System.out.println("存在333...:");
                //存在就结束
                return;
            }
            //获取实体类包名
            String[] strs = cl.getName().split("\\.");
            String packageName = "";
            //去掉类名
            for(int i=0;i<strs.length-1;i++) {
                packageName += "."+strs[i];
            }
            packageName = packageName.replaceFirst(".", "");
            //获取模板
            Configuration configuration = new Configuration(Configuration.getVersion());
            configuration.setClassForTemplateLoading(GeneratorDaoUtil.class, templateDir);
            //configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "填你的resource下的路径,比如/ftl"));
            Template template = configuration.getTemplate(templateName);
            // 创建数据模型
            HashMap<String, Object> root = new HashMap<String, Object>();
            //action包名
            if(!CommonTool.checkNotNull(urlData.getActionUrl())) {
                System.err.println("没有生成action路径");
                return;
            }
            root.put("packageName",urlData.getActionUrl()[1]);
            //实体类的类名
            root.put("entityName", entityName);
            //实体类的类名(首字母小写)
            root.put("entityNameSmall", entityNameSmall);
            //dao的包名
            if(!CommonTool.checkNotNull(urlData.getDaoUrl())) {
                System.err.println("没有dao路径");
                return;
            }
            if(!CommonTool.checkNotNull(urlData.getTotalUrl())) {
                System.err.println("没有设置总包路径");
                return;
            }
            root.put("TotalPackageName",urlData.getTotalUrl());
            root.put("DAOPackageName",urlData.getDaoUrl()[1]);
            //实体类的包名
            root.put("entityPackageName",packageName);
            System.out.println("actionUrl:"+targetFile);
            // 将模板和数据模型合并 输出到Console
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile), "UTF-8"));
            template.process(root, out);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
hx_auto/src/main/java/com.hx.auto/GeneratorMapperUtil.java
New file
@@ -0,0 +1,176 @@
package com.hx.auto;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.zip.ZipOutputStream;
import com.gitee.sunchenbin.mybatis.actable.annotation.Column;
import com.gitee.sunchenbin.mybatis.actable.annotation.Table;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import com.hx.auto.common.JdbcType;
import com.hx.auto.common.ReadEntityData;
import com.hx.auto.common.UrlData;
import com.hx.auto.util.CommonTool;
import com.hx.auto.util.GeneratorClassParentUtil;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
/**
 * 自动生成mapper.xml
 *
 * @author chenjiahe 2019年09月08日23:57:47
 *
 */
public class GeneratorMapperUtil {
    private static String templateDir = "/ftl";//获取模板路径
    private static String templateName = "Mapper.tpl";//action模板名称
    /**生成mapper.xml
     * @param cl 实体类
     * @param urlData 生成配置信息
     * @throws Exception
     */
    public static void generatorMapper(Class<?> cl,UrlData urlData) throws Exception {
        try {
            // 反射start
            // 类名
            String entityName = cl.getSimpleName();
            // 类名首字母小写
            String initial = entityName.substring(0, 1).toLowerCase();
            String entityNameSmall = initial + entityName.substring(1, entityName.length());
            //获取实体类包名
            String[] strs = cl.getName().split("\\.");
            String packageName = "";
            //去掉类名
            for(int i=0;i<strs.length-1;i++) {
                packageName += "."+strs[i];
            }
            packageName = packageName.replaceFirst(".", "");
            //获取模板
            Configuration configuration = new Configuration(Configuration.getVersion());
            configuration.setClassForTemplateLoading(GeneratorMapperUtil.class, templateDir);
            //configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "填你的resource下的路径,比如/ftl"));
            Template template = configuration.getTemplate(templateName);
            //实体类所有的字段
            //用来存储数据
            ReadEntityData readEntityData = new ReadEntityData();
            //表名称
            Table table = cl.getAnnotation(Table.class);
            readEntityData.setTableName(table.name());
            // 取得本类的全部属性
            Field[] fields = cl.getDeclaredFields();
            fields = GeneratorClassParentUtil.getPatentFields(fields,cl);
            for (Field field:fields) {
                // 判断方法中是否有指定注解类型的注解
                boolean hasAnnotation = field.isAnnotationPresent(Column.class);
                if (hasAnnotation) {
                    // 根据注解类型返回方法的指定类型注解
                    Column column = field.getAnnotation(Column.class);
                    //判断是不是
                    boolean isBol = false;
                    Integer isBlob = 0;
                    if(column.type().equals(MySqlTypeConstant.TEXT)||column.type().equals(MySqlTypeConstant.LONGTEXT)
                    ||column.type().equals(MySqlTypeConstant.LONGBLOB)){
                        isBol = true;
                        isBlob = 1;
                    }
                    //类型
                    //String type = column.type().toUpperCase();
                    String type = JdbcType.jdbcTypeData(field.getType().getTypeName().toUpperCase(),isBol);
                    //主键
                    if (column.isKey()) {
                        readEntityData.setEntityIdName(field.getName());
                        readEntityData.setEntityIdData("#{"+field.getName()+"}");
                        if(!CommonTool.checkNotNull(column.name())) {
                            readEntityData.setTableIdName(field.getName());
                        }else {
                            readEntityData.setTableIdName(column.name());
                        }
                        readEntityData.setKeyType(type);
                        continue;
                    }
                    //存储数据
                    if(!CommonTool.checkNotNull(column.name())) {
                        readEntityData.fielData(field.getName(),field.getName(),type,isBlob,"#{"+field.getName()+"}");
                    }else {
                        readEntityData.fielData(field.getName(),column.name(),type,isBlob,"#{"+field.getName()+"}");
                    }
                }
            }
            // 创建数据模型
            HashMap<String, Object> root = new HashMap<String, Object>();
            //action包名
            if(!CommonTool.checkNotNull(urlData.getActionUrl())) {
                System.err.println("没有生成action路径");
                return;
            }
            if(!CommonTool.checkNotNull(urlData.getTotalUrl())) {
                System.err.println("没有设置总包路径");
                return;
            }
            root.put("TotalPackageName",urlData.getTotalUrl());
            root.put("packageActionName",urlData.getActionUrl()[1]);
            root.put("packageEntityName",packageName);
            //实体类的类名
            root.put("entityName", entityName);
            //实体类的类名(首字母小写)
            root.put("entityNameSmall", entityNameSmall);
            //表字段 数据
            root.put("fieldData",readEntityData);
            root.put("sqlSentence","${sqlSentence}");
            //root.put("sqlSentence","${sqlSentence}");
            //root.put("sqlSentence","${sqlSentence}");
            //dao的包名
            if(!CommonTool.checkNotNull(urlData.getDaoUrl())) {
                System.err.println("没有dao路径");
                return;
            }
            root.put("DAOPackageName",urlData.getDaoUrl()[1]);
            //实体类的包名
            root.put("entityPackageName",packageName);
            //生成文件路径
            String targetFile = urlData.getMapperUrl()[1].replace(".", "/")+"/";
            //生成文件名称
            targetFile += entityName + "Mapper.xml";
            //补全路径
            targetFile = "./"+urlData.getMapperUrl()[0].replace(".", "/")+"/"+targetFile;
            //获取是否已经生成过文件,拿取自定义的内容
            String xmlStr = GeneratorReadXmlUtil.readMapperXml(targetFile);
            if(!"false".equals(xmlStr)){
                root.put("customData",GeneratorReadXmlUtil.readMapperXml(targetFile));
            }else{
                root.put("customData","");
            }
            System.out.println("mapperUrl:"+targetFile);
            // 将模板和数据模型合并 输出到Console
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile), "UTF-8"));
            template.process(root, out);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
hx_auto/src/main/java/com.hx.auto/GeneratorServiceUtil.java
New file
@@ -0,0 +1,121 @@
package com.hx.auto;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import com.hx.auto.common.UrlData;
import com.hx.auto.util.CommonTool;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
/**
 * 自动生成Service and ServiceImpl
 *
 * @author chenjiahe 2019年09月08日16:57:47
 *
 */
public class GeneratorServiceUtil {
    private static String templateDir = "/ftl";//获取模板路径
    private static String templateServiceName = "Service.tpl";//service名称
    private static String templateServiceImplName = "ServiceImpl.tpl";//serviceImpl名称
    /**
     * @param cl 实体类
     * @param urlData 配置信息
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    public static void generatorService(Class<?> cl, UrlData urlData) throws Exception {
        try {
            //获取类的包名
            String className = cl.getSimpleName();
            String[] strs = cl.getName().split("\\.");
            String packageName = "";
            for(int i=0;i<strs.length-1;i++) {
                packageName += "."+strs[i];
            }
            packageName = packageName.replaceFirst(".","");
            // 类名首字母小写
            String initial = className.substring(0, 1).toLowerCase();
            String classNamex = initial + className.substring(1, className.length());
            // 取得本类的全部属性
            String targetFile = urlData.getServiceUrl()[1].replace(".", "/")+"/";
            targetFile += className + "Service.java";
            //补全路径
            targetFile = "./"+urlData.getServiceUrl()[0].replace(".", "/")+"/"+targetFile;
            File fileService = new File(targetFile);
            if(fileService.exists()){
                //存在就结束
                return;
            }
            String targetFile2 = urlData.getServiceImplUrl()[1].replace(".", "/")+"/";
            targetFile2 += className + "ServiceImpl.java";
            //补全路径
            targetFile2 = "./"+urlData.getServiceImplUrl()[0].replace(".", "/")+"/"+targetFile2;
            File fileServiceImple = new File(targetFile2);
            if(fileServiceImple.exists()){
                System.out.println("fileServiceImple:"+targetFile2);
                //存在就结束
                return;
            }
            //获取模板
            Configuration configuration = new Configuration(Configuration.getVersion());
            configuration.setClassForTemplateLoading(GeneratorServiceUtil.class, templateDir);
            //configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "填你的resource下的路径,比如/ftl"));
            // 获取或创建模板
            Template template = configuration.getTemplate(templateServiceName);
            // 创建数据模型
            HashMap<String, Object> root = new HashMap<String, Object>();
            root.put("className", classNamex);
            root.put("classNameUP", className);
            root.put("packageName", packageName);
            root.put("servicePack", urlData.getServiceUrl()[1]);
            root.put("actionPack", urlData.getActionUrl()[1]);
            System.out.println("serviceUrl:"+targetFile);
            // 将模板和数据模型合并 输出到Console
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile), "UTF-8"));
            template.process(root, out);
            out.flush();
            out.close();
            if(!CommonTool.checkNotNull(urlData.getTotalUrl())) {
                System.err.println("没有设置总包路径");
                return;
            }
            root.put("TotalPackageName",urlData.getTotalUrl());
            root.put("serviceImpPack", urlData.getServiceImplUrl()[1]);
            root.put("daoPack", urlData.getDaoUrl()[1]);
            //serviceImp文件
            // 获取或创建模板
            Template template2 = configuration.getTemplate(templateServiceImplName);
            System.out.println("serviceImpUrl:"+targetFile2);
            // 将模板和数据模型合并 输出到Console
            Writer out2 = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile2), "UTF-8"));
            template2.process(root, out2);
            out2.flush();
            out2.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
    }
}
hx_auto/src/main/java/com.hx.auto/GeneratorUtil.java
New file
@@ -0,0 +1,256 @@
package com.hx.auto;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import com.gitee.sunchenbin.mybatis.actable.annotation.Table;
import com.hx.auto.common.UrlData;
/**
 * 自动生成工具
 * 2019-08-29
 * @author hx
 *
 */
public class GeneratorUtil {
    public static void main(String[] args) throws Exception {
        System.out.println("开始");
        UrlData urlData = new UrlData();
        urlData.setTotalUrl("com.hx");
        urlData.actionUrlData("src.main.java","com.hx.controller.admin");
        urlData.daoUrlData("src.main.java","com.hx.dao.mapper");
        urlData.serviceUrlData("src.main.java","com.hx.service");
        urlData.serviceImplUrlData("src.main.java","com.hx.service.impl");
        urlData.mapperUrlData("src.main.java", "com.hx.dao.mapperXml");
        /*//dao
        generatorDao(SysAdmin.class,urlData);
        //mapper
        generatorMapper(SysAdmin.class, urlData);
        //action
        generatorAction(SysAdmin.class,urlData);
        // 生成service
        generatorService(SysAdmin.class,urlData);*/
        //generatorTableByPackUrl(packPath, urlData);
        /*Class cl = TestM2.class;
        Field[] fields = cl.getDeclaredFields();
        for(Field field:fields) {
            System.out.println("field.getName():"+field.getName());
            System.out.println("field.getType():"+field.getType());
            System.out.println("field.getGenericType():"+field.getGenericType());
            System.out.println("field.getModifiers():"+field.getModifiers());
        }*/
        //StringBuffer stringBuffer = SimpleToolUtil.getFileContent("com/hx/auto/file/test.txt");
        //System.out.println("stringBuffer:"+stringBuffer);
    }
    /**通过包路径获取xml和mapper
     *
     * @param packPath 包路径
     * @param urlData 生成文件的配置
     */
    public static <T> void generatorXmlAndMapper(String packPath,UrlData urlData) {
        try {
            Set<Class<?>> classes = classData(packPath);
            for(Class<?> cl:classes) {
                //action
                //generatorAction(cl,urlData);
                //dao
                generatorDao(cl,urlData);
                //mapper.xml
                generatorMapper(cl, urlData);
                // 生成service
                //generatorService(cl,urlData);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**通过包路径获取所有文件
     *
     * @param packPath 包路径
     * @param urlData 生成文件的配置
     */
    public static <T> void generatorTableByPackUrl(String packPath,UrlData urlData) {
        try {
            Set<Class<?>> classes = classData(packPath);
            for(Class<?> cl:classes) {
                //action
                generatorAction(cl,urlData);
                //dao
                generatorDao(cl,urlData);
                //mapper.xml
                generatorMapper(cl, urlData);
                // 生成service
                generatorService(cl,urlData);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**自动生成dao文件
     *
     * @param cl 指定生成类
     * @param urlData 生成文件的配置文件
     */
    public static <T> void generatorDao(Class<?> cl,UrlData urlData) {
        try {
            //判断是否有标志,没有标志就跳过
            if (null != cl.getAnnotation(Table.class)) {
                // 生成action
                GeneratorDaoUtil.generatorDao(cl,urlData);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**自动生成mapper.xml文件
     *
     * @param cl 指定生成类
     * @param urlData 生成文件的配置文件
     */
    public static <T> void generatorMapper(Class<?> cl,UrlData urlData) {
        try {
            //判断是否有标志,没有标志就跳过
            if (null != cl.getAnnotation(Table.class)) {
                // 生成action
                GeneratorMapperUtil.generatorMapper(cl, urlData);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**自动生成action文件
     *
     * @param cl 指定生成类
     * @param urlData 生成文件的配置文件
     */
    public static <T> void generatorAction(Class<?> cl,UrlData urlData) {
        try {
            //生成动态sql的文件(sqlSentence.java),已经生成就不用生成,否则会覆盖
            /*if(sqlParam) {
                GeneratorsqlSentenceUtil.GeneratorsqlSentence(urlData);
            }*/
            //判断是否有标志,没有标志就跳过
            if (null != cl.getAnnotation(Table.class)) {
                // 生成action
                GeneratorActionUtil.generatorAction(cl, urlData, false);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**自动生成Service and ServiceImpl文件
     *
     * @param cl 指定生成类
     * @param urlData 生成文件的配置文件
     */
    public static <T> void generatorService(Class<?> cl,UrlData urlData) {
        try {
            //判断是否有标志,没有标志就跳过
            if (null != cl.getAnnotation(Table.class)) {
                // 生成action
                GeneratorServiceUtil.generatorService(cl,urlData);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**获取包下面的所有文件*/
    public static Set<Class<?>> classData(String packPath){
        Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
        // 是否循环迭代
        boolean recursive = true;
        // 获取包的名字 并进行替换
        String packageName = packPath;
        String packageDirName = packageName.replace('.', '/');
        // 定义一个枚举的集合 并进行循环来处理这个目录下的things
        Enumeration<URL> dirs;
        try{
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            // 循环迭代下去
            while (dirs.hasMoreElements()){
                // 获取下一个元素
                URL url = dirs.nextElement();
                // 得到协议的名称
                String protocol = url.getProtocol();
                // 如果是以文件的形式保存在服务器上
                if ("file".equals(protocol)) {
                    System.err.println("file类型的扫描:" + packPath);
                    // 获取包的物理路径
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    // 以文件的方式扫描整个包下的文件 并添加到集合中
                    findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        return classes;
    }
    /**
     * 以文件的形式来获取包下的所有Class
     *
     * @param packageName
     * @param packagePath
     * @param recursive
     * @param classes
     */
    public static void findAndAddClassesInPackageByFile(
            String packageName,
            String packagePath,
            final boolean recursive,
            Set<Class<?>> classes){
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter(){
            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
            public boolean accept(File file){
                return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
            }
        });
        // 循环所有文件
        for (File file : dirfiles){
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
            }else{
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0, file.getName().length() - 6);
                try{
                    // 添加到集合中去
                    // classes.add(Class.forName(packageName + '.' +
                    // className));
                    // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                }catch (ClassNotFoundException e){
                    // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
                    e.printStackTrace();
                }
            }
        }
    }
}
hx_auto/src/main/java/com.hx.auto/common/JdbcType.java
New file
@@ -0,0 +1,51 @@
package com.hx.auto.common;
/**javaType和jdbcType对比
 *
 * @author chenjiahe
 *
 */
public class JdbcType {
    /**
     * @param type 字段类型
     * @param isBol 是否长字符串
     * @return
     */
    public static String jdbcTypeData(String type,boolean isBol) {
        //字母转化为小字母
        type = type.toLowerCase();
        if(type.equals("java.lang.string")) {
            if(!isBol) {
                type = "VARCHAR";
            }else {
                type = "LONGVARCHAR";
            }
        }else if(type.equals("int")) {
            type = "INTEGER";
        }else if(type.equals("java.lang.integer")) {
            type = "INTEGER";
        }else if(type.equals("boolean")) {
            type = "BOOLEAN";
        }else if(type.equals("byte")) {
            type = "TINYINT";
        }else if(type.equals("short")) {
            type = "SMALLINT";
        }else if(type.equals("long")) {
            type = "BIGINT";
        }else if(type.equals("float")) {
            type = "REAL";
        }else if(type.equals("double")) {
            type = "DOUBLE";
        }else if(type.equals("java.lang.double")) {
            type = "DOUBLE";
        }else if(type.equals("java.util.date")) {
            type = "TIMESTAMP";
        }else if(type.equals("java.sql.date")) {
            type = "TIMESTAMP";
        }else if(type.equals("blob")) {
            type = "BLOB";
        }
        return type;
    }
}
hx_auto/src/main/java/com.hx.auto/common/Lob.java
New file
@@ -0,0 +1,25 @@
package com.hx.auto.common;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**长字符串
 * @author chenjiahe
 * @version 2019年09月14日 下午6:13:37
 */
//表示注解加在接口、类、枚举等
@Target(ElementType.TYPE)
//VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
@Retention(RetentionPolicy.RUNTIME)
//将此注解包含在javadoc中
@Documented
//允许子类继承父类中的注解
@Inherited
public @interface Lob {
}
hx_auto/src/main/java/com.hx.auto/common/ReadEntityData.java
New file
@@ -0,0 +1,154 @@
package com.hx.auto.common;
import java.util.ArrayList;
import java.util.List;
/**实体类对应生成mapper.xml的数据*/
public class ReadEntityData {
    //实体类的主键id名称
    private String entityIdName;
    //表的主键id名称
    private String tableIdName;
    //主键类型
    private String keyType;
    //表的名称
    private String tableName;
    //实体类和表的所有字段名称(除了主键)
    private List<FieldAttribute> fields = new ArrayList<FieldAttribute>();
    //特殊字段,主键id,如:#{id}
    private String entityIdData;
    //特殊字段,mybatis的排序
    private String orderBy = "${orderBy}";
    //特殊字段,mybatis的实体类匹配表字段
    private String createData = "#{createData.obj}";
    //特殊字段,mybatis的传的值
    private String valueData = "#{value}";
    /********************************************************************/
    /** 存储实体类的表字段
     * @param entityName 实体类字段名称
     * @param tableName1 表名称
     * @param dataType 类型
     */
    public void fielData(String entityName,String tableName1,String dataType,Integer isBlob,String mybatisName) {
        fields.add(new FieldAttribute(entityName,tableName1, dataType,isBlob,mybatisName));
    }
    /******************************************************************/
    public String getEntityIdName() {
        return entityIdName;
    }
    public void setEntityIdName(String entityIdName) {
        this.entityIdName = entityIdName;
    }
    public String getTableIdName() {
        return tableIdName;
    }
    public void setTableIdName(String tableIdName) {
        this.tableIdName = tableIdName;
    }
    public String getTableName() {
        return tableName;
    }
    public void setTableName(String tableName) {
        this.tableName = tableName;
    }
    public List<FieldAttribute> getFields() {
        return fields;
    }
    public void setFields(List<FieldAttribute> fields) {
        this.fields = fields;
    }
    public String getOrderBy() {
        return orderBy;
    }
    public void setOrderBy(String orderBy) {
        this.orderBy = orderBy;
    }
    public String getKeyType() {
        return keyType;
    }
    public void setKeyType(String keyType) {
        this.keyType = keyType;
    }
    public String getCreateData() {
        return createData;
    }
    public void setCreateData(String createData) {
        this.createData = createData;
    }
    public String getValueData() {
        return valueData;
    }
    public void setValueData(String valueData) {
        this.valueData = valueData;
    }
    public String getEntityIdData() {
        return entityIdData;
    }
    public void setEntityIdData(String entityIdData) {
        this.entityIdData = entityIdData;
    }
    /*****************************************************************/
    public static class FieldAttribute {
        //实体类字段名称
        private String entityName;
        //表字段名称
        private String tableName;
        //数据库类型
        private String dataType;
        //是否大数据
        private Integer isBlob = 0;
        //特殊字段,如在mybati中 #{id}的表示
        private String mybatisName;
        /**********************************/
        public FieldAttribute(String entityName,String tableName,String dataType,Integer isBlob
                ,String mybatisName) {
            this.entityName = entityName;
            this.tableName = tableName;
            this.dataType = dataType;
            this.isBlob = isBlob;
            this.mybatisName = mybatisName;
        }
        /*********************************/
        public String getDataType() {
            return dataType;
        }
        public void setDataType(String dataType) {
            this.dataType = dataType;
        }
        public String getEntityName() {
            return entityName;
        }
        public void setEntityName(String entityName) {
            this.entityName = entityName;
        }
        public String getTableName() {
            return tableName;
        }
        public void setTableName(String tableName) {
            this.tableName = tableName;
        }
        public Integer getIsBlob() {
            return isBlob;
        }
        public void setIsBlob(Integer isBlob) {
            this.isBlob = isBlob;
        }
        public String getMybatisName() {
            return mybatisName;
        }
        public void setMybatisName(String mybatisName) {
            this.mybatisName = mybatisName;
        }
    }
}
hx_auto/src/main/java/com.hx.auto/common/UrlData.java
New file
@@ -0,0 +1,105 @@
package com.hx.auto.common;
/**属性保存*/
public class UrlData {
    /**总包*/
    private String totalUrl;
    /**生成action的包路径*/
    private String[] actionUrl;
    /**生成mapper.xml路径*/
    private String[] mapperUrl;
    /**生成DAO的包路径*/
    private String[] daoUrl;
    /**生成service接口的包路径*/
    private String[] serviceUrl;
    /**生成serviceImpl接口的包路径*/
    private String[] serviceImplUrl;
    /**********************************/
    /**
     * 一下类引入的路径需要
     * @param totalUrl 总包,如:com.songSir
     */
    public void  totalUrlData(String totalUrl){
        this.totalUrl = totalUrl;
    }
    /**生成action的包路径
     * @param packRoot 根目录,如:src.main.java
     * @param actionPack 包目录,如:com.songSir.model
     */
    public void actionUrlData(String packRoot,String actionPack) {
        actionUrl = new String[] {packRoot,actionPack};
    }
    /**生成mapper.xml路径
     *
     * @param packRoot 根目录,如:src.main.java
     * @param mapperPack 包目录/文件目录,如:com.songSir.mapper 或者 com/songSir/mapper
     */
    public void mapperUrlData(String packRoot,String mapperPack) {
        mapperUrl = new String[] {packRoot,mapperPack};
    }
    /**生成DAO的包路径
     *
     * @param packRoot 根目录,如:src.main.java
     * @param daoPack 包目录,如:com.songSir.dao
     */
    public void daoUrlData(String packRoot,String daoPack) {
        daoUrl = new String[] {packRoot,daoPack};
    }
    /**生成service接口的包路径
     *
     * @param packRoot 根目录,如:src.main.java
     * @param servicePack 包目录,如:com.songSir.service
     */
    public void serviceUrlData(String packRoot,String servicePack) {
        serviceUrl = new String[] {packRoot,servicePack};
    }
    /**生成service接口的包路径
     *
     * @param packRoot 根目录,如:src.main.java
     * @param serviceImpUrlPack 包目录,如:com.songSir.serviceImp
     */
    public void serviceImplUrlData(String packRoot,String serviceImpUrlPack) {
        serviceImplUrl = new String[] {packRoot,serviceImpUrlPack};
    }
    /*********************************/
    public String[] getActionUrl() {
        return actionUrl;
    }
    public void setActionUrl(String[] actionUrl) {
        this.actionUrl = actionUrl;
    }
    public String[] getMapperUrl() {
        return mapperUrl;
    }
    public void setMapperUrl(String[] mapperUrl) {
        this.mapperUrl = mapperUrl;
    }
    public String[] getDaoUrl() {
        return daoUrl;
    }
    public void setDaoUrl(String[] daoUrl) {
        this.daoUrl = daoUrl;
    }
    public String[] getServiceUrl() {
        return serviceUrl;
    }
    public void setServiceUrl(String[] serviceUrl) {
        this.serviceUrl = serviceUrl;
    }
    public String[] getServiceImplUrl() {
        return serviceImplUrl;
    }
    public void setServiceImplUrl(String[] serviceImplUrl) {
        this.serviceImplUrl = serviceImplUrl;
    }
    public String getTotalUrl() {
        return totalUrl;
    }
    public void setTotalUrl(String totalUrl) {
        this.totalUrl = totalUrl;
    }
}
hx_auto/src/main/java/com/hx/auto/GeneratorReadXmlUtil.java
New file
@@ -0,0 +1,192 @@
package com.hx.auto;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.*;
/**
 * 自动生成Service and ServiceImpl
 *
 * @author chenjiahe 2020-06-28
 *
 */
public class GeneratorReadXmlUtil {
    /**
     *
     * @param targetFile 文件路径
     * @return 返回自定义的sql
     */
    public static String readMapperXml(String  targetFile) throws ParserConfigurationException, IOException, SAXException {
        String temp = "";
        //映射文件的文件夹
        File file = new File(targetFile);
        if(!file.exists()){
            return "false";
        }
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(file);
        Node Node= doc.getLastChild();
        NodeList nodeList = Node.getChildNodes();
        String comment = "";
        for(int i=0;i<nodeList.getLength();i++) {
            //从节点集中获取i个book节点
            Node childNode = nodeList.item(i);
            //获取子节点内的文本内容
            String content = childNode.getTextContent();
            //获取节点名
            String name = childNode.getNodeName();
            //System.out.println("content:"+content+";name:"+name);
            //System.out.println("name....:"+name);
            if(!"#text".equals(name)&&!"#comment".equals(name)){
                //获取第一个节点内的所有属性
                NamedNodeMap nameNodeMap = childNode.getAttributes();
                //获取节点内名为id的属性的值
                String id = nameNodeMap.getNamedItem("id").getTextContent();
                if(isCustom(nameNodeMap.getNamedItem("id").getTextContent())){
                    String con = NodetoString(childNode);
                    //去掉附带的内容
                    con = con.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>","");
                    String con2 = con;
                    con = con.replaceAll("\t","").replaceAll("\n","");
                    if(con.length()>3){
                        con= con2;
                    }
                    temp+=comment+"\n\t"+con;
                }
                comment = "";
            }else{
                String con = NodetoString(childNode);
                //去掉附带的内容
                con = con.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>","");
                String con2 = con;
                //去掉多余的
                con = con.replaceAll("\t","").replaceAll("\n","");
                if(con.length()>5){
                    comment+= con2;
                }
            }
        }
        System.out.println("temp:...:"+temp);
        return temp;
    }
    public static boolean isCustom(String id){
        boolean custom = true;
        Set<String> noCustomIds = new HashSet<String>();
        noCustomIds.add("BaseResultMap");
        noCustomIds.add("Entity_Id");
        noCustomIds.add("Table_Id");
        noCustomIds.add("Table_Name");
        noCustomIds.add("Base_Column_List");
        noCustomIds.add("Blob_Column_List");
        noCustomIds.add("Insert_Column_All");
        noCustomIds.add("Update_Column_All");
        noCustomIds.add("Update_Column_NoNull");
        noCustomIds.add("keyFind");
        noCustomIds.add("insert");
        noCustomIds.add("insertById");
        noCustomIds.add("selectList");
        noCustomIds.add("selectListBlob");
        noCustomIds.add("selectOne");
        noCustomIds.add("selectOneBlob");
        noCustomIds.add("selectOneByKey");
        noCustomIds.add("selectOneByKeyBlob");
        noCustomIds.add("updateWhere");
        noCustomIds.add("updateAll");
        noCustomIds.add("updateByNoNull");
        noCustomIds.add("deleteWhere");
        noCustomIds.add("deleteById");
        noCustomIds.add("selectCount");
        noCustomIds.add("Insert_Values_All");
        noCustomIds.add("selectListMap");
        noCustomIds.add("selectOneMap");
        noCustomIds.add("selectCountSql");
        if (noCustomIds.contains(id)){
            custom = false;
        }
        return custom;
    }
    /*
     * 把dom文件转换为xml字符串
     */
    public static String toStringFromDoc(Document document) throws IOException {
        String result = null;
        if (document != null) {
            StringWriter strWtr = new StringWriter();
            StreamResult strResult = new StreamResult(strWtr);
            TransformerFactory tfac = TransformerFactory.newInstance();
            try {
                javax.xml.transform.Transformer t = tfac.newTransformer();
                t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
                t.setOutputProperty(OutputKeys.INDENT, "yes");
                t.setOutputProperty(OutputKeys.METHOD, "xml"); // xml, html,
// text
                t.setOutputProperty(
                        "{http://xml.apache.org/xslt}indent-amount", "4");
                t.transform(new DOMSource(document.getDocumentElement()),
                        strResult);
            } catch (Exception e) {
                System.err.println("XML.toString(Document): " + e);
            }
            result = strResult.getWriter().toString();
            strWtr.close();
        }
        return result;
    }
    /**
     * 将传入的一个DOM Node对象输出成字符串。如果失败则返回一个空字符串""。
     *
     * @param node
     *            DOM Node 对象。
     * @return a XML String from node
     */
    public static String NodetoString(Node node) {
        Transformer transformer = null;
        String result = null;
        if (node == null) {
            throw new IllegalArgumentException();
        }
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        if (transformer != null) {
            try {
                StringWriter sw = new StringWriter();
                transformer.transform(new DOMSource(node), new StreamResult(sw));
                return sw.toString();
            } catch (TransformerException te) {
                throw new RuntimeException(te.getMessage());
            }
        }
        return result;
    }
}
hx_auto/src/main/java/com/hx/auto/file/Action.tpl
New file
@@ -0,0 +1,79 @@
package ${packageName};
import java.util.List;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hx.common.BaseController;
import com.hx.mybatisTool.SqlSentence;
import ${DAOPackageName}.${entityName}Mapper;
import ${entityPackageName}.${entityName};
import ${servicePackageName}.${entityName}Service;
import com.hx.resultTool.Result;
import com.hx.util.SimpleTool;
import net.sf.json.JSONObject;
import com.hx.phitab.common.AuthConstants;
@RestController
@RequestMapping("${entityNameSmall}")
public class ${entityName}Controller extends BaseController {
    @Resource
    private ${entityName}Service service;
    /**列表*/
    @Authority(tag = AuthConstants.${entityName}.SEE)
    @RequestMapping("/list")
    public Result listData(Integer pageNum,Integer pageSize) {
        //pageNum当前第几页
        //rowCount 拿几条
        //分页插件
         PageHelper.startPage(pageNum==null?1:pageNum,pageSize==null?20:pageSize);
        SqlSentence sqlSentence = new SqlSentence();
        List<${entityName}> ${entityNameSmall}s = service.selectList(sqlSentence);
        PageInfo pageInfo = new PageInfo<${entityName}>(${entityNameSmall}s);
        Map<String,Object> data = new HashMap<>();
        data.put("pageNum",pageInfo.getPageNum());
        data.put("pageSize",pageInfo.getPageSize());
        data.put("total",pageInfo.getTotal());
        data.put("isLastPage",pageInfo.isIsLastPage());
        data.put("list",pageInfo.getList());
        return Result.success(data);
    }
    /**新增*/
    @Authority(tag = AuthConstants.${entityName}.ADD)
    @RequestMapping("/add")
    public Result addData(${entityName} ${entityNameSmall}) {
        service.insert(${entityNameSmall});
        return Result.success();
    }
    /**获取数据*/
    @Authority(tag = AuthConstants.${entityName}.SEE)
    @RequestMapping("/see")
    public Result editeData(String id) {
        ${entityName} ${entityNameSmall} = service.selectOneByKeyBlob(id);
        return Result.success(${entityNameSmall});
    }
    /**修改数据*/
    @Authority(tag = AuthConstants.${entityName}.EDIT)
    @RequestMapping("/update")
    public Result updateData(${entityName} ${entityNameSmall}) {
        service.updateAll(${entityNameSmall});
        return Result.success();
    }
    /**删除数据(单个)*/
    @Authority(tag = AuthConstants.${entityName}.DELETE)
    @RequestMapping("/delete/one")
    public Result deleteData(String id) {
        service.deleteOne(id);
        return Result.success();
    }
}
hx_auto/src/main/java/com/hx/auto/file/Dao.tpl
New file
@@ -0,0 +1,35 @@
package ${DAOPackageName};
import java.util.List;
import java.util.Map;
import com.hx.mybatisTool.SqlSentence;
import ${entityPackageName}.${entityName};
public interface ${entityName}Mapper {
    /**新增,返回主键*/
    int insert(${entityName} ${entityNameSmall});
    /**新增,返回主键*/
    int insertById(${entityName} ${entityNameSmall});
    /**查询条数*/
    int selectCount(SqlSentence sqlSentence);
    /**查询列表,返回实体类的List*/
    List<${entityName}> selectList(SqlSentence sqlSentence);
    /**查询列表,返回Map的List*/
    List<Map<String,Object>> selectListMap(SqlSentence sqlSentence);
    /**查询,返回单个实体*/
    ${entityName} selectOne(SqlSentence sqlSentence);
    /**查询,返回单个map*/
    Map<String,Object> selectOneMap(SqlSentence sqlSentence);
    /**查询,返回实体类没有大数据的*/
    ${entityName} selectOneByKey(Object object);
    /**查询,返回实体类有大数据的*/
    ${entityName} selectOneByKeyBlob(Object object);
    /**更新,返回更新数量*/
    int updateWhere(SqlSentence sqlSentence);
    /**更新,返回更新数量*/
    int updateAll(${entityName} ${entityNameSmall});
    /**删除,返回删除数量*/
    int deleteWhere(SqlSentence sqlSentence);
    /**删除,返回删除数量*/
    int deleteById(Object object);
}
hx_auto/src/main/java/com/hx/auto/file/Mapper.tpl
New file
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:该mapper.xml映射文件的 唯一标识 -->
<mapper namespace="${DAOPackageName}.${entityName}Mapper">
    <!-- 整个实体类修改,表字段=实体类字段-->
    <sql id="Update_Column_All">
        <trim prefixOverrides=",">
            <#list fieldData.fields as item>,${item.tableName} = ${item.mybatisName}</#list>
        </trim>
    </sql>
    <!--  后续通过  namespace.id-->
    <!--parameterType:输入参数的类型
    resultType:查询返回结果值的类型  ,返回类型  -->
    <insert id="insert" parameterType="${packageEntityName}.${entityName}">
        <selectKey keyProperty="id" resultType="String" order="BEFORE">
            select replace(uuid(),'-','') from dual
        </selectKey>
        insert into ${fieldData.tableName} (${fieldData.tableIdName}<#list fieldData.fields as item>,${item.tableName}</#list>)
        values (${fieldData.entityIdData}<#list fieldData.fields as item>,${item.mybatisName}</#list>)
    </insert>
    <select id="selectList" resultType="${packageEntityName}.${entityName}" parameterType="com.hx.mybatisTool.SqlSentence" >
        ${sqlSentence}
    </select>
    <select id="selectListMap" resultType="java.util.Map" parameterType="com.hx.mybatisTool.SqlSentence" >
            ${sqlSentence}
    </select>
    <select id="selectOne" resultType="${packageEntityName}.${entityName}" parameterType="com.hx.mybatisTool.SqlSentence" >
        ${sqlSentence}
    </select>
    <select id="selectOneMap" resultType="java.util.Map" parameterType="com.hx.mybatisTool.SqlSentence" >
            ${sqlSentence}
    </select>
    <select id="selectCount" resultType="int" parameterType="com.hx.mybatisTool.SqlSentence" >
            select
                COUNT(*)
            from ${fieldData.tableName}
                WHERE ${sqlSentence}
    </select>
    <select id="selectOneByKey" resultType="${packageEntityName}.${entityName}" parameterType="java.lang.Object" >
        select
            ${fieldData.tableIdName}<#list fieldData.fields as item>,${item.tableName}</#list>
        from ${fieldData.tableName}
        WHERE ${fieldData.tableIdName} = ${fieldData.valueData}
    </select>
    <select id="selectOneByKeyBlob" resultType="${packageEntityName}.${entityName}" parameterType="java.lang.Object" >
        select
            ${fieldData.tableIdName}<#list fieldData.fields as item>,${item.tableName}</#list>
        from ${fieldData.tableName}
        WHERE ${fieldData.tableIdName} = ${fieldData.valueData}
    </select>
    <update id="updateWhere" parameterType="com.hx.mybatisTool.SqlSentence">
        update
            ${fieldData.tableName}
        SET ${sqlSentence}
    </update>
    <update id="updateAll" parameterType="${packageEntityName}.${entityName}">
        update ${fieldData.tableName}
            SET <include refid="Update_Column_All"/>
        WHERE ${fieldData.tableIdName} = ${fieldData.entityIdData}
    </update>
    <delete id="deleteWhere"  parameterType="com.hx.mybatisTool.SqlSentence">
        delete from ${fieldData.tableName} WHERE ${sqlSentence}
    </delete>
    <delete id="deleteById"  parameterType="java.lang.Object">
        delete from ${fieldData.tableName} WHERE ${fieldData.tableIdName} = ${fieldData.valueData}
    </delete>
    ${customData}
</mapper>
hx_auto/src/main/java/com/hx/auto/file/Service.tpl
New file
@@ -0,0 +1,33 @@
package ${servicePack};
import ${packageName}.${classNameUP};
import com.hx.mybatisTool.SqlSentence;
import java.util.List;
import java.util.Map;
public interface ${classNameUP}Service {
    int selectCount(SqlSentence sqlSentence);
    void insert(${classNameUP} ${className});
    List<${classNameUP}> selectList(SqlSentence sqlSentence);
    List<Map<String,Object>> selectListMap(SqlSentence sqlSentence);
    ${classNameUP} selectOne(SqlSentence sqlSentence);
    Map<String,Object> selectOneMap(SqlSentence sqlSentence);
    ${classNameUP} selectOneByKey(Object object);
    ${classNameUP} selectOneByKeyBlob(Object object);
    void updateAll(${classNameUP} ${className});
    void updateWhere(SqlSentence sqlSentence);
    void deleteOne(String delId);
}
hx_auto/src/main/java/com/hx/auto/file/ServiceImpl.tpl
New file
@@ -0,0 +1,101 @@
package ${serviceImpPack};
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.hx.exception.TipsException;
import ${daoPack}.${classNameUP}Mapper;
import ${packageName}.${classNameUP};
import ${servicePack}.${classNameUP}Service;
import com.hx.mybatisTool.SqlSentence;
import java.util.List;
import java.util.Map;
@Transactional
@Service
public class ${classNameUP}ServiceImpl implements ${classNameUP}Service {
    @Resource
    private ${classNameUP}Mapper ${className}Mapper;
    /**查询列表*/
    @Override
    public List<${classNameUP}> selectList(SqlSentence sqlSentence) {
        return ${className}Mapper.selectList(sqlSentence);
    }
    /**查询列表*/
    @Override
    public List<Map<String,Object>> selectListMap(SqlSentence sqlSentence) {
        return ${className}Mapper.selectListMap(sqlSentence);
    }
    /**查询单个*/
    @Override
    public ${classNameUP} selectOne(SqlSentence sqlSentence) {
        return ${className}Mapper.selectOne(sqlSentence);
    }
    /**查询单个*/
    @Override
    public Map<String,Object> selectOneMap(SqlSentence sqlSentence) {
        return ${className}Mapper.selectOneMap(sqlSentence);
    }
    /**查询单个,大数据不拿取*/
    @Override
    public ${classNameUP} selectOneByKey(Object object) {
        return ${className}Mapper.selectOneByKey(object);
    }
    /**查询单个,大数据拿取*/
    @Override
    public ${classNameUP} selectOneByKeyBlob(Object object) {
        return ${className}Mapper.selectOneByKeyBlob(object);
    }
    /**新增*/
    @Override
    public void insert(${classNameUP} ${className}) {
        int count = ${className}Mapper.insert(${className});
        if(count != 1) {
            throw new TipsException("新增失败!");
        }
    }
    /**修改*/
    @Override
    public void updateAll(${classNameUP} ${className}) {
        int count = ${className}Mapper.updateAll(${className});
        if(count!=1) {
            throw new TipsException("保存失败!");
        }
    }
    /**修改*/
    @Override
    public void updateWhere(SqlSentence sqlSentence) {
        int count = ${className}Mapper.updateWhere(sqlSentence);
        if(count!=1) {
            throw new TipsException("保存失败!");
        }
    }
    /**删除一个*/
    @Override
    public void deleteOne(String delId) {
        int count = ${className}Mapper.deleteById(delId);
        if(count!=1) {
            throw new TipsException("删除失败!");
        }
    }
    /**查询条数*/
    @Override
    public int selectCount(SqlSentence sqlSentence) {
        int count = ${className}Mapper.selectCount(sqlSentence);
        return count;
    }
}
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/StartScanXmlHandler.java
New file
@@ -0,0 +1,15 @@
package com.hx.auto.manage.xml.scan;
/**
 * 启动时执行处理的接口
 * @author chenbin.sun
 *
 */
public interface StartScanXmlHandler {
    /**
     * 建表开始
     */
    void startHandler() throws Exception;
}
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/StartScanXmlHandlerImpl.java
New file
@@ -0,0 +1,34 @@
package com.hx.auto.manage.xml.scan;
import com.hx.auto.GeneratorUtil;
import com.hx.auto.manage.xml.scan.util.ConfigUtil;
import com.hx.auto.manage.xml.scan.util.CreateMapperUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Set;
/**
 * 启动时进行处理的实现类
 * @author chenbin.sun
 *
 */
@SuppressWarnings("restriction")
@Service
public class StartScanXmlHandlerImpl implements StartScanXmlHandler {
    @Autowired
    private ConfigUtil configUtil;
    @PostConstruct
    public void startHandler() throws Exception {
        if(configUtil.getIsScan()){
            System.out.println("开始扫描更新xml文件");
            Set<Class<?>> classes = GeneratorUtil.classData(configUtil.getModelPack());
            for(Class<?> cl:classes) {
                CreateMapperUtil.generatorMapper(cl,configUtil);
            }
        }
    }
}
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/util/ConfigUtil.java
New file
@@ -0,0 +1,145 @@
package com.hx.auto.manage.xml.scan.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.PropertyResourceConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.support.PropertiesLoaderSupport;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Properties;
@Component
public class ConfigUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    private static Properties properties = null;
    @Value(Constants.CJH_SCAN_XML_SUPPLY)
    private String isScan;
    @Value(Constants.CJH_PACKAGE_FILE_NAME_URL)
    private String packFileName;
    @Value(Constants.CJH_PACKAGE_MODEL_URL)
    private String modelPack;
    @Value(Constants.CJH_CREATE_XML_URL)
    private String xmlUrl;
    @Value(Constants.CJH_CREATE_DAO_URL)
    private String daoUrl;
    /**
     * 实现ApplicationContextAware接口的回调方法,设置上下文环境
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        ConfigUtil.applicationContext = applicationContext;
    }
    /**
     * 获得spring上下文
     *
     * @return ApplicationContext spring上下文
     */
    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    /**
     * 获取bean
     *
     * @param name
     *            service注解方式name为小驼峰格式
     * @return Object bean的实例对象
     */
    public Object getBean(String name) throws BeansException {
        return applicationContext.getBean(name);
    }
    private void initProperties() {
        properties = new Properties();
        try {
            String[] postProcessorNames = applicationContext.getBeanNamesForType(BeanFactoryPostProcessor.class, true,
                    true);
            for (String ppName : postProcessorNames) {
                BeanFactoryPostProcessor beanProcessor = applicationContext.getBean(ppName,
                        BeanFactoryPostProcessor.class);
                if (beanProcessor instanceof PropertyResourceConfigurer) {
                    PropertyResourceConfigurer propertyResourceConfigurer = (PropertyResourceConfigurer) beanProcessor;
                    Method mergeProperties = PropertiesLoaderSupport.class.getDeclaredMethod("mergeProperties");
                    mergeProperties.setAccessible(true);
                    Properties props = (Properties) mergeProperties.invoke(propertyResourceConfigurer);
                    // get the method convertProperties
                    // in class PropertyResourceConfigurer
                    Method convertProperties = PropertyResourceConfigurer.class.getDeclaredMethod("convertProperties",
                            Properties.class);
                    // convert properties
                    convertProperties.setAccessible(true);
                    convertProperties.invoke(propertyResourceConfigurer, props);
                    properties.putAll(props);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static Properties getProperties() {
        return properties;
    }
    public static void setProperties(Properties properties) {
        ConfigUtil.properties = properties;
    }
    public String getModelPack() {
        return modelPack;
    }
    public void setModelPack(String modelPack) {
        this.modelPack = modelPack;
    }
    public Boolean getIsScan() {
        return "true".equals(isScan);
    }
    public void setIsScan(String isScan) {
        this.isScan = isScan;
    }
    public String getPackFileName() {
        return packFileName;
    }
    public void setPackFileName(String packFileName) {
        this.packFileName = packFileName;
    }
    public String getXmlUrl() {
        return xmlUrl;
    }
    public void setXmlUrl(String xmlUrl) {
        this.xmlUrl = xmlUrl;
    }
    public String getDaoUrl() {
        return daoUrl;
    }
    public void setDaoUrl(String daoUrl) {
        this.daoUrl = daoUrl;
    }
}
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/util/Constants.java
New file
@@ -0,0 +1,18 @@
package com.hx.auto.manage.xml.scan.util;
public class Constants {
    /**是否扫描补充xml文件*/
    public static final String CJH_SCAN_XML_SUPPLY                    = "${xml.scan.xml.supply}";
    /**项目名称*/
    public static final String CJH_PROJECT_NAME                     = "${xml.priject.name}";
    /**包所在的文件夹路径*/
    public static final String CJH_PACKAGE_FILE_NAME_URL             = "${xml.package.file.name}";
    /**生成DAO路径*/
    public static final String CJH_CREATE_DAO_URL                     = "${xml.create.dao.url}";
    /**生成路径*/
    public static final String CJH_CREATE_XML_URL                     = "${xml.create.xml.url}";
    /**实体类包路径*/
    public static final String CJH_PACKAGE_MODEL_URL                 = "${xml.model.name}";
}
hx_auto/src/main/java/com/hx/auto/manage/xml/scan/util/CreateMapperUtil.java
New file
@@ -0,0 +1,154 @@
package com.hx.auto.manage.xml.scan.util;
import com.gitee.sunchenbin.mybatis.actable.annotation.Column;
import com.gitee.sunchenbin.mybatis.actable.annotation.Table;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import com.hx.auto.GeneratorMapperUtil;
import com.hx.auto.GeneratorReadXmlUtil;
import com.hx.auto.common.JdbcType;
import com.hx.auto.common.ReadEntityData;
import com.hx.auto.util.CommonTool;
import com.hx.auto.util.GeneratorClassParentUtil;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
/**
 * 自动生成mapper.xml
 *
 * @author chenjiahe 2019年09月08日23:57:47
 *
 */
public class CreateMapperUtil {
    private static String templateDir = "/ftl";//获取模板路径
    private static String templateName = "Mapper.tpl";//action模板名称
    /**生成mapper.xml
     * @param cl 实体类
     * @param configUtil 生成配置信息
     * @throws Exception
     */
    public static void generatorMapper(Class<?> cl, ConfigUtil configUtil) throws Exception {
        try {
            // 反射start
            // 类名
            String entityName = cl.getSimpleName();
            //生成文件路径
            String targetFile = configUtil.getXmlUrl().replace(".", "/")+"/";
            //生成文件名称
            targetFile += entityName + "Mapper.xml";
            //补全路径
            targetFile = "./"+configUtil.getPackFileName().replace(".", "/")+"/"+targetFile;
            //获取是否已经生成过文件,拿取自定义的内容
            String xmlData = GeneratorReadXmlUtil.readMapperXml(targetFile);
            //如果不存在就直接跳过
            if("false".equals(xmlData)){
                return;
            }
            // 类名首字母小写
            String initial = entityName.substring(0, 1).toLowerCase();
            String entityNameSmall = initial + entityName.substring(1, entityName.length());
            //获取实体类包名
            String[] strs = cl.getName().split("\\.");
            String packageName = "";
            //去掉类名
            for(int i=0;i<strs.length-1;i++) {
                packageName += "."+strs[i];
            }
            packageName = packageName.replaceFirst(".", "");
            //获取模板
            Configuration configuration = new Configuration(Configuration.getVersion());
            configuration.setClassForTemplateLoading(GeneratorMapperUtil.class, templateDir);
            // 获取或创建模板
            Template template = configuration.getTemplate(templateName);
            //实体类所有的字段
            //用来存储数据
            ReadEntityData readEntityData = new ReadEntityData();
            //表名称
            Table table = cl.getAnnotation(Table.class);
            readEntityData.setTableName(table.name());
            // 取得本类的全部属性
            Field[] fields = cl.getDeclaredFields();
            fields = GeneratorClassParentUtil.getPatentFields(fields,cl);
            for (Field field:fields) {
                // 判断方法中是否有指定注解类型的注解
                boolean hasAnnotation = field.isAnnotationPresent(Column.class);
                if (hasAnnotation) {
                    // 根据注解类型返回方法的指定类型注解
                    Column column = field.getAnnotation(Column.class);
                    //判断是不是
                    boolean isBol = false;
                    Integer isBlob = 0;
                    if(column.type().equals(MySqlTypeConstant.TEXT)||column.type().equals(MySqlTypeConstant.LONGTEXT)
                    ||column.type().equals(MySqlTypeConstant.LONGBLOB)){
                        isBol = true;
                        isBlob = 1;
                    }
                    //类型
                    //String type = column.type().toUpperCase();
                    String type = JdbcType.jdbcTypeData(field.getType().getTypeName().toUpperCase(),isBol);
                    //主键
                    if (column.isKey()) {
                        readEntityData.setEntityIdName(field.getName());
                        readEntityData.setEntityIdData("#{"+field.getName()+"}");
                        if(!CommonTool.checkNotNull(column.name())) {
                            readEntityData.setTableIdName(field.getName());
                        }else {
                            readEntityData.setTableIdName(column.name());
                        }
                        readEntityData.setKeyType(type);
                        continue;
                    }
                    //存储数据
                    if(!CommonTool.checkNotNull(column.name())) {
                        readEntityData.fielData(field.getName(),field.getName(),type,isBlob,"#{"+field.getName()+"}");
                    }else {
                        readEntityData.fielData(field.getName(),column.name(),type,isBlob,"#{"+field.getName()+"}");
                    }
                }
            }
            // 创建数据模型
            HashMap<String, Object> root = new HashMap<String, Object>();
            root.put("packageEntityName",packageName);
            //实体类的类名
            root.put("entityName", entityName);
            //实体类的类名(首字母小写)
            root.put("entityNameSmall", entityNameSmall);
            //表字段 数据
            root.put("fieldData",readEntityData);
            root.put("sqlSentence","${sqlSentence}");
            root.put("DAOPackageName",configUtil.getDaoUrl());
            //实体类的包名
            root.put("entityPackageName",packageName);
            //获取是否已经生成过文件,拿取自定义的内容
            root.put("customData",xmlData);
            System.out.println("mapperUrl:"+targetFile);
            // 将模板和数据模型合并 输出到Console
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile), "UTF-8"));
            template.process(root, out);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
hx_auto/src/main/java/com/hx/auto/util/CommonTool.java
New file
@@ -0,0 +1,17 @@
package com.hx.auto.util;
public class CommonTool {
    /**
     * 判断是否为空
     */
    public static boolean checkNotNull(Object o) {
        boolean b = false;
        if (o != null && !"".equals(o)&&!"undefind".equals(o)) {
            b = true;
        }
        return b;
    }
}
hx_auto/src/main/java/com/hx/auto/util/GeneratorClassParentUtil.java
New file
@@ -0,0 +1,55 @@
package com.hx.auto.util;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.*;
/**
 *
 * @author chenjiahe 2020-06-28
 *
 */
public class GeneratorClassParentUtil {
    /**
     * 获取父类的字段
     * @param fields
     * @param clas
     * @return
     */
    public static Field[] getPatentFields(Field[] fields,Class<?> clas){
        if (clas.getSuperclass() != null) {
            Class clsSup = clas.getSuperclass();
            List<Field> fieldList = new ArrayList<Field>();
            fieldList.addAll(Arrays.asList(fields));
            fieldList.addAll(Arrays.asList(clsSup.getDeclaredFields()));
            fields = new Field[fieldList.size()];
            int i = 0;
            for (Object field : fieldList.toArray()) {
                fields[i] = (Field) field;
                i++;
            }
            fields = getPatentFields(fields,clsSup);
        }
        return  fields;
    }
}
hx_auto/src/main/resources/ftl/Action.tpl
New file
@@ -0,0 +1,79 @@
package ${packageName};
import java.util.List;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hx.common.BaseController;
import com.hx.mybatisTool.SqlSentence;
import ${DAOPackageName}.${entityName}Mapper;
import ${entityPackageName}.${entityName};
import ${servicePackageName}.${entityName}Service;
import com.hx.resultTool.Result;
import com.hx.util.SimpleTool;
import net.sf.json.JSONObject;
import com.hx.phitab.common.AuthConstants;
@RestController
@RequestMapping("${entityNameSmall}")
public class ${entityName}Controller extends BaseController {
    @Resource
    private ${entityName}Service service;
    /**列表*/
    @Authority(tag = AuthConstants.${entityName}.SEE)
    @RequestMapping("/list")
    public Result listData(Integer pageNum,Integer pageSize) {
        //pageNum当前第几页
        //rowCount 拿几条
        //分页插件
         PageHelper.startPage(pageNum==null?1:pageNum,pageSize==null?20:pageSize);
        SqlSentence sqlSentence = new SqlSentence();
        List<${entityName}> ${entityNameSmall}s = service.selectList(sqlSentence);
        PageInfo pageInfo = new PageInfo<${entityName}>(${entityNameSmall}s);
        Map<String,Object> data = new HashMap<>();
        data.put("pageNum",pageInfo.getPageNum());
        data.put("pageSize",pageInfo.getPageSize());
        data.put("total",pageInfo.getTotal());
        data.put("isLastPage",pageInfo.isIsLastPage());
        data.put("list",pageInfo.getList());
        return Result.success(data);
    }
    /**新增*/
    @Authority(tag = AuthConstants.${entityName}.ADD)
    @RequestMapping("/add")
    public Result addData(${entityName} ${entityNameSmall}) {
        service.insert(${entityNameSmall});
        return Result.success();
    }
    /**获取数据*/
    @Authority(tag = AuthConstants.${entityName}.SEE)
    @RequestMapping("/see")
    public Result editeData(String id) {
        ${entityName} ${entityNameSmall} = service.selectOneByKeyBlob(id);
        return Result.success(${entityNameSmall});
    }
    /**修改数据*/
    @Authority(tag = AuthConstants.${entityName}.EDIT)
    @RequestMapping("/update")
    public Result updateData(${entityName} ${entityNameSmall}) {
        service.updateAll(${entityNameSmall});
        return Result.success();
    }
    /**删除数据(单个)*/
    @Authority(tag = AuthConstants.${entityName}.DELETE)
    @RequestMapping("/delete/one")
    public Result deleteData(String id) {
        service.deleteOne(id);
        return Result.success();
    }
}
hx_auto/src/main/resources/ftl/Dao.tpl
New file
@@ -0,0 +1,37 @@
package ${DAOPackageName};
import java.util.List;
import java.util.Map;
import com.hx.mybatisTool.SqlSentence;
import ${entityPackageName}.${entityName};
public interface ${entityName}Mapper {
    /**新增,返回主键*/
    int insert(${entityName} ${entityNameSmall});
    /**新增,返回主键*/
    int insertById(${entityName} ${entityNameSmall});
    /**查询条数*/
    int selectCount(SqlSentence sqlSentence);
    /**查询条数*/
    int selectCountSql(SqlSentence sqlSentence);
    /**查询列表,返回实体类的List*/
    List<${entityName}> selectList(SqlSentence sqlSentence);
    /**查询列表,返回Map的List*/
    List<Map<String,Object>> selectListMap(SqlSentence sqlSentence);
    /**查询,返回单个实体*/
    ${entityName} selectOne(SqlSentence sqlSentence);
    /**查询,返回单个map*/
    Map<String,Object> selectOneMap(SqlSentence sqlSentence);
    /**查询,返回实体类没有大数据的*/
    ${entityName} selectOneByKey(Object object);
    /**查询,返回实体类有大数据的*/
    ${entityName} selectOneByKeyBlob(Object object);
    /**更新,返回更新数量*/
    int updateWhere(SqlSentence sqlSentence);
    /**更新,返回更新数量*/
    int updateAll(${entityName} ${entityNameSmall});
    /**删除,返回删除数量*/
    int deleteWhere(SqlSentence sqlSentence);
    /**删除,返回删除数量*/
    int deleteById(Object object);
}
hx_auto/src/main/resources/ftl/Mapper.tpl
New file
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:该mapper.xml映射文件的 唯一标识 -->
<mapper namespace="${DAOPackageName}.${entityName}Mapper">
    <!-- 整个实体类修改,表字段=实体类字段-->
    <sql id="Update_Column_All">
        <trim prefixOverrides=",">
            <#list fieldData.fields as item>,${item.tableName} = ${item.mybatisName}</#list>
        </trim>
    </sql>
    <!--  后续通过  namespace.id-->
    <!--parameterType:输入参数的类型
    resultType:查询返回结果值的类型  ,返回类型  -->
    <insert id="insert" parameterType="${packageEntityName}.${entityName}">
        <selectKey keyProperty="id" resultType="String" order="BEFORE">
               select replace(uuid(),'-','') from dual
        </selectKey>
        insert into ${fieldData.tableName} (${fieldData.tableIdName}<#list fieldData.fields as item>,${item.tableName}</#list>)  values (${fieldData.entityIdData}<#list fieldData.fields as item>,${item.mybatisName}</#list>)
    </insert>
    <insert id="insertById" parameterType="${packageEntityName}.${entityName}">
        insert into ${fieldData.tableName} (${fieldData.tableIdName}<#list fieldData.fields as item>,${item.tableName}</#list>)  values (${fieldData.entityIdData}<#list fieldData.fields as item>,${item.mybatisName}</#list>)
    </insert>
    <select id="selectList" resultType="${packageEntityName}.${entityName}" parameterType="com.hx.mybatisTool.SqlSentence" >
        ${sqlSentence}
    </select>
    <select id="selectListMap" resultType="java.util.Map" parameterType="com.hx.mybatisTool.SqlSentence" >
            ${sqlSentence}
    </select>
    <select id="selectOne" resultType="${packageEntityName}.${entityName}" parameterType="com.hx.mybatisTool.SqlSentence" >
        ${sqlSentence}
    </select>
    <select id="selectOneMap" resultType="java.util.Map" parameterType="com.hx.mybatisTool.SqlSentence" >
            ${sqlSentence}
    </select>
    <select id="selectCount" resultType="int" parameterType="com.hx.mybatisTool.SqlSentence" >
            select
                COUNT(*)
            from ${fieldData.tableName}
                WHERE ${sqlSentence}
    </select>
    <select id="selectCountSql" resultType="int" parameterType="com.hx.mybatisTool.SqlSentence" >
            ${sqlSentence}
     </select>
    <select id="selectOneByKey" resultType="${packageEntityName}.${entityName}" parameterType="java.lang.Object" >
        select
            ${fieldData.tableIdName}<#list fieldData.fields as item>,${item.tableName}</#list>
        from ${fieldData.tableName}
        WHERE ${fieldData.tableIdName} = ${fieldData.valueData}
    </select>
    <select id="selectOneByKeyBlob" resultType="${packageEntityName}.${entityName}" parameterType="java.lang.Object" >
        select
            ${fieldData.tableIdName}<#list fieldData.fields as item>,${item.tableName}</#list>
        from ${fieldData.tableName}
        WHERE ${fieldData.tableIdName} = ${fieldData.valueData}
    </select>
    <update id="updateWhere" parameterType="com.hx.mybatisTool.SqlSentence">
        update
            ${fieldData.tableName}
        SET ${sqlSentence}
    </update>
    <update id="updateAll" parameterType="${packageEntityName}.${entityName}">
        update ${fieldData.tableName}
            SET <include refid="Update_Column_All"/>
        WHERE ${fieldData.tableIdName} = ${fieldData.entityIdData}
    </update>
    <delete id="deleteWhere"  parameterType="com.hx.mybatisTool.SqlSentence">
        delete from ${fieldData.tableName} WHERE ${sqlSentence}
    </delete>
    <delete id="deleteById"  parameterType="java.lang.Object">
        delete from ${fieldData.tableName} WHERE ${fieldData.tableIdName} = ${fieldData.valueData}
    </delete>
    ${customData}
</mapper>
hx_auto/src/main/resources/ftl/Service.tpl
New file
@@ -0,0 +1,33 @@
package ${servicePack};
import ${packageName}.${classNameUP};
import com.hx.mybatisTool.SqlSentence;
import java.util.List;
import java.util.Map;
public interface ${classNameUP}Service {
    int selectCount(SqlSentence sqlSentence);
    void insert(${classNameUP} ${className});
    List<${classNameUP}> selectList(SqlSentence sqlSentence);
    List<Map<String,Object>> selectListMap(SqlSentence sqlSentence);
    ${classNameUP} selectOne(SqlSentence sqlSentence);
    Map<String,Object> selectOneMap(SqlSentence sqlSentence);
    ${classNameUP} selectOneByKey(Object object);
    ${classNameUP} selectOneByKeyBlob(Object object);
    void updateAll(${classNameUP} ${className});
    void updateWhere(SqlSentence sqlSentence);
    void deleteOne(String delId);
}
hx_auto/src/main/resources/ftl/ServiceImpl.tpl
New file
@@ -0,0 +1,101 @@
package ${serviceImpPack};
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.hx.exception.TipsException;
import ${daoPack}.${classNameUP}Mapper;
import ${packageName}.${classNameUP};
import ${servicePack}.${classNameUP}Service;
import com.hx.mybatisTool.SqlSentence;
import java.util.List;
import java.util.Map;
@Transactional
@Service
public class ${classNameUP}ServiceImpl implements ${classNameUP}Service {
    @Resource
    private ${classNameUP}Mapper ${className}Mapper;
    /**查询列表*/
    @Override
    public List<${classNameUP}> selectList(SqlSentence sqlSentence) {
        return ${className}Mapper.selectList(sqlSentence);
    }
    /**查询列表*/
    @Override
    public List<Map<String,Object>> selectListMap(SqlSentence sqlSentence) {
        return ${className}Mapper.selectListMap(sqlSentence);
    }
    /**查询单个*/
    @Override
    public ${classNameUP} selectOne(SqlSentence sqlSentence) {
        return ${className}Mapper.selectOne(sqlSentence);
    }
    /**查询单个*/
    @Override
    public Map<String,Object> selectOneMap(SqlSentence sqlSentence) {
        return ${className}Mapper.selectOneMap(sqlSentence);
    }
    /**查询单个,大数据不拿取*/
    @Override
    public ${classNameUP} selectOneByKey(Object object) {
        return ${className}Mapper.selectOneByKey(object);
    }
    /**查询单个,大数据拿取*/
    @Override
    public ${classNameUP} selectOneByKeyBlob(Object object) {
        return ${className}Mapper.selectOneByKeyBlob(object);
    }
    /**新增*/
    @Override
    public void insert(${classNameUP} ${className}) {
        int count = ${className}Mapper.insert(${className});
        if(count != 1) {
            throw new TipsException("新增失败!");
        }
    }
    /**修改*/
    @Override
    public void updateAll(${classNameUP} ${className}) {
        int count = ${className}Mapper.updateAll(${className});
        if(count!=1) {
            throw new TipsException("保存失败!");
        }
    }
    /**修改*/
    @Override
    public void updateWhere(SqlSentence sqlSentence) {
        int count = ${className}Mapper.updateWhere(sqlSentence);
        if(count!=1) {
            throw new TipsException("保存失败!");
        }
    }
    /**删除一个*/
    @Override
    public void deleteOne(String delId) {
        int count = ${className}Mapper.deleteById(delId);
        if(count!=1) {
            throw new TipsException("删除失败!");
        }
    }
    /**查询条数*/
    @Override
    public int selectCount(SqlSentence sqlSentence) {
        int count = ${className}Mapper.selectCount(sqlSentence);
        return count;
    }
}
hx_common/.gitignore
New file
@@ -0,0 +1,25 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/target/
/.idea
hx_common/pom.xml
New file
@@ -0,0 +1,327 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.hx.gitee</groupId>
        <artifactId>hx-parent</artifactId>
        <version>stander</version>
    </parent>
    <artifactId>hx-common</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!--对象与XML处理-->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
        </dependency>
      <!--  <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.9</version>
            <exclusions>
                <exclusion>
                    <artifactId>dom4j</artifactId>
                    <groupId>dom4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>-->
        <!--腾讯云 cos-->
        <dependency>
            <groupId>com.qcloud</groupId>
            <artifactId>cos_api</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
        </dependency>
        <!--发送邮件-->
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-csv</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
        </dependency>
        <dependency>
            <groupId>com.huaweicloud</groupId>
            <artifactId>esdk-obs-java</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
        </dependency>
        <!--微信支付用到的包-->
        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jdom</groupId>
            <artifactId>jdom</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
        </dependency>
        <!--<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </dependency>-->
        <!--生成二维码支持包-->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
        </dependency>
        <dependency>
            <groupId>net.glxn</groupId>
            <artifactId>qrgen</artifactId>
        </dependency>
        <!-- 字符串工具类jar:StringUtils -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>jstl-api</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <!--<scope>provided</scope>-->
        </dependency>
        <!-- mybatis自动生成 -->
        <dependency>
            <groupId>com.gitee.sunchenbin.mybatis.actable</groupId>
            <artifactId>mybatis-enhance-actable</artifactId>
        </dependency>
        <!-- 模板生成jar -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>jcl-over-slf4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-validator</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId><exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <classifier>jdk15</classifier>
        </dependency>
        <dependency>
            <groupId>com.belerweb</groupId>
            <artifactId>pinyin4j</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.jexcelapi</groupId>
            <artifactId>jxl</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sf.ezmorph</groupId>
            <artifactId>ezmorph</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
        </dependency>
        <dependency>
            <groupId>com.dtflys.forest</groupId>
            <artifactId>spring-boot-starter-forest</artifactId>
            <version>1.5.0-RC2</version>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.monitorjbl/xlsx-streamer -->
        <dependency>
            <groupId>com.monitorjbl</groupId>
            <artifactId>xlsx-streamer</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>hx-common</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                    <include>**/*.tld</include>
                    <include>**/*.tpl</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>profile-active/**</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>${runtime.env}</directory>
            </resource>
        </resources>
    </build>
</project>
hx_common/src/main/java/com/hx/annotation/Jurisdiction.java
New file
@@ -0,0 +1,25 @@
package com.hx.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**权限注解
 * @author chenjiahe
 * @version 2019年09月14日 下午6:13:37
 */
//表示注解加在接口、类、枚举等
@Target(ElementType.METHOD)
//VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
@Retention(RetentionPolicy.RUNTIME)
//将此注解包含在javadoc中
@Documented
//允许子类继承父类中的注解
@Inherited
public @interface Jurisdiction {
    /**权限名*/
     String privilege();
}
hx_common/src/main/java/com/hx/api/CorpMpSpaceApi.java
New file
@@ -0,0 +1,196 @@
package com.hx.api;
import com.alibaba.fastjson.JSONObject;
import com.dtflys.forest.annotation.DataVariable;
import com.dtflys.forest.annotation.JSONBody;
import com.dtflys.forest.annotation.Post;
/**
 * 企业微信微盘接口API
 * @Author: cmg
 * @Date: 2023-7-13 11:08
 */
public interface CorpMpSpaceApi {
    /**
     * 增加空间
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_create?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject addSpace(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 重命名空间
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_rename?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject renameSpace(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 解散空间
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_dismiss?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject dismissSpace(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 空间安全设置
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_setting?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject spaceSetting(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 新建文件夹/文档
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_create?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject createFile(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 文件重命名
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_rename?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject renameFile(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 移除文件
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_delete?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject deleteFile(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 分块上传初始化
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_upload_init?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject fileUploadInit(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 分块上传文件
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_upload_part?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject fileUploadPart(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 分块上传完成
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_upload_finish?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject fileUploadFinish(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 上传文件
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_upload?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject fileUpload(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 删除文件
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_delete?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject fileDelete(@DataVariable("accessToken") String accessToken, @JSONBody String param);
    /**
     * 获取下载路径
     * @param accessToken
     * @param param
     * @return
     */
    @Post(
            url = "https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_download?access_token=${accessToken}",
            headers = {
                    "Content-Type: application/json"
            }
    )
    JSONObject getDownloadUrl(@DataVariable("accessToken") String accessToken, @JSONBody String param);
}
hx_common/src/main/java/com/hx/bean/annotations/MysqlAutoAes.java
New file
@@ -0,0 +1,25 @@
package com.hx.bean.annotations;
import com.hx.mybatis.aes.springbean.ConstantBean;
import com.hx.mybatis.aes.springbean.InitMysqlData;
import com.hx.mybatis.aes.springbean.MySqlInterceptor;
import com.hx.mybatis.aes.springbean.VariableAesKey;
import com.hx.security.request.RequestRestriction;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**自动加Mysql的AES加密程序
 *这里的Import的两个类就是需要加载的bean,这样就可以通过简单的添加一个注解来加载自己自定义的bean了,而且可
 *以是很多个,可以打到jar包里面通过Maven引入都是ok的;
 * @author CJH
 * @date 202-06-17
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ConstantBean.class, InitMysqlData.class, MySqlInterceptor.class, VariableAesKey.class})
public @interface MysqlAutoAes {
}
hx_common/src/main/java/com/hx/bean/annotations/RedisClient.java
New file
@@ -0,0 +1,26 @@
package com.hx.bean.annotations;
import com.hx.mybatis.aes.springbean.ConstantBean;
import com.hx.mybatis.aes.springbean.InitMysqlData;
import com.hx.mybatis.aes.springbean.MySqlInterceptor;
import com.hx.mybatis.aes.springbean.VariableAesKey;
import com.hx.redis.RedisConfig;
import com.hx.redis.RedisUtil;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**使用redis链接
 *这里的Import的两个类就是需要加载的bean,这样就可以通过简单的添加一个注解来加载自己自定义的bean了,而且可
 *以是很多个,可以打到jar包里面通过Maven引入都是ok的;
 * @author CJH
 * @date 202-06-17
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({RedisConfig.class, RedisUtil.class})
public @interface RedisClient {
}
hx_common/src/main/java/com/hx/bean/annotations/RequestSecurity.java
New file
@@ -0,0 +1,21 @@
package com.hx.bean.annotations;
import com.hx.security.request.RequestRestriction;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**请求安全bean加载
 *这里的Import的两个类就是需要加载的bean,这样就可以通过简单的添加一个注解来加载自己自定义的bean了,而且可
 *以是很多个,可以打到jar包里面通过Maven引入都是ok的;
 * @author CJH
 * @date 202-06-17
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({RequestRestriction.class})
public @interface RequestSecurity {
}
hx_common/src/main/java/com/hx/common/BaseController.java
New file
@@ -0,0 +1,88 @@
package com.hx.common;
import com.hx.common.service.CommonService;
import com.hx.exception.ParamException;
import com.hx.exception.ServiceException;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.WebRequest;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**公共初始化
 * @author ChenJiaHe
 * @Date 2020-06-11
 */
public class BaseController {
    @Resource
    protected CommonService commonService;
    /*请不要声明变量,会导致不安全,因为这个是单列*/
    //只需要加上下面这段即可,注意不能忘记注解
    @InitBinder
    public void initBinder(WebDataBinder binder, WebRequest request) {
        //转换日期 注意这里的转化要和传进来的字符串的格式一直 如2015-9-9 就应该为yyyy-MM-dd
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));// CustomDateEditor为自定义日期编辑器
    }
    public HttpServletRequest getRequest() {
        //获取参数对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes.getRequest();
    }
    public HttpSession getSession() {
        //获取参数对象
        return getRequest() .getSession();
    }
    /**
     * 获取request里某个属性
     * @param attrName 属性名称
     * @return 对象
     */
    public Object getRequestAttribute(String attrName)
    {
        return getRequest().getAttribute(attrName);
    }
    /**
     * 设置一个request属性
     * @param attrName 属性名称
     * @param attrObject 属性值
     */
    public void setRequestAttribute(String attrName, Object attrObject) {
        getRequest().setAttribute(attrName, attrObject);
    }
    /**
     * 抛出服务异常
     * @param msg 错误信息
     */
    public void throwServiceException(String msg)
    {
        throw new ServiceException(msg);
    }
    /**
     * 抛出参数异常
     * @param msg 错误信息
     */
    public void throwParamException(String msg)
    {
        throw new ParamException(msg);
    }
}
hx_common/src/main/java/com/hx/common/annotations/MysqlHexAes.java
New file
@@ -0,0 +1,24 @@
package com.hx.common.annotations;
import java.lang.annotation.*;
/**
 * 指定mysql的AES加密字段
 * @author CJH
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MysqlHexAes {
    /**秘钥-没有就是配置文件设置*/
    String aesKey() default "";
    /**数据库数据初始化版本*/
    String initVersion() default "";
    /**xml生成查询解密*/
    boolean selectDec() default false;
    /**xml更新加密*/
    boolean updateDec() default false;
    /**xml新增加密*/
    boolean insertDec() default false;
}
hx_common/src/main/java/com/hx/common/annotations/repeat/RequestRepeat.java
New file
@@ -0,0 +1,17 @@
package com.hx.common.annotations.repeat;
import java.lang.annotation.*;
/**
 * 重复校验注解
 * @author CJH
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestRepeat {
    /**是否重复校验,默认true*/
    boolean isRepeat() default true;
    /**重复间隔时间,毫秒,默认1000毫秒*/
    long millisecond() default 1000;
}
hx_common/src/main/java/com/hx/common/dao/CommonDao.java
New file
@@ -0,0 +1,127 @@
package com.hx.common.dao;
import com.hx.mybatisTool.SqlSentence;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
 * dao通用接口
 * @author ChenJiaHe
 * @Date 2020-10-14
 */
public interface CommonDao {
    /**新增,返回主键
     * @param mapperClass mapper类
     * @param entity 实体类
     * @return 条数
     */
    <T extends Serializable>    int insert(Class<?> mapperClass, T entity);
    /**新增,返回主键
     * @param mapperClass mapper类
     * @param entity 实体类
     * @return 条数
     */
    <T extends Serializable>    int insertById(Class<?> mapperClass, T entity);
    /**查询条数
     * @param mapperClass mapper类
     * @param sqlSentence  查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int selectCount(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询条数
     * @param mapperClass mapper类
     * @param sqlSentence  查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int selectCountSql(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询列表,返回实体类的List
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回list
     */
    <T extends Serializable> List<T> selectList(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询列表,返回Map的List
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return Map的List
     */
    <T extends Serializable> List<Map<String,Object>> selectListMap(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询,返回单个实体
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回实体类
     */
    <T extends Serializable> T selectOne(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询,返回单个map
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回实体类
     */
    <T extends Serializable> Map<String,Object> selectOneMap(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询,返回实体类没有大数据的
     * @param mapperClass mapper类
     * @param object 数据标识key
     * @return 返回实体类
     */
    <T extends Serializable> T selectOneByKey(Class<?> mapperClass, Object object);
    /**查询,返回实体类有大数据的
     * @param mapperClass mapper类
     * @param object 数据标识key
     * @return 返回实体类
     */
    <T extends Serializable> T selectOneByKeyBlob(Class<?> mapperClass, Object object);
    /**更新,返回更新数量
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int updateWhere(Class<?> mapperClass, SqlSentence sqlSentence);
    /**更新,返回更新数量
     * @param mapperClass mapper类
     * @param entity 实体类
     * @return 返回条数
     */
    <T extends Serializable> int updateAll(Class<?> mapperClass, T entity);
    /**删除,返回删除数量
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int deleteWhere(Class<?> mapperClass, SqlSentence sqlSentence);
    /**删除,返回删除数量
     * @param mapperClass mapper类
     * @param object 数据标识key
     * @return 返回条数
     */
    <T extends Serializable> int deleteById(Class<?> mapperClass, Object object);
    /**更新sql语句(全语句)
     * @param sqlSentence 查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int updateSentence( SqlSentence sqlSentence);
    /**查询条数语句(全语句)
     * @param sqlSentence 查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int selectCountSql( SqlSentence sqlSentence);
}
hx_common/src/main/java/com/hx/common/dao/mapper/CommonMapper.java
New file
@@ -0,0 +1,20 @@
package com.hx.common.dao.mapper;
import com.hx.mybatisTool.SqlSentence;
import java.util.List;
import java.util.Map;
public interface CommonMapper {
    /**更新,返回更新数量*/
    int updateSentence(SqlSentence sqlSentence);
    /**查询列表,返回Map的List*/
    List<Map<String,Object>> selectListMap(SqlSentence sqlSentence);
    /**查询,返回条数数量*/
    int selectCountSql(SqlSentence sqlSentence);
}
hx_common/src/main/java/com/hx/common/service/CommonService.java
New file
@@ -0,0 +1,127 @@
package com.hx.common.service;
import com.hx.mybatisTool.SqlSentence;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
 * dao通用接口
 * @author ChenJiaHe
 * @Date 2020-10-14
 */
public interface CommonService {
    /**新增,返回主键
     * @param mapperClass mapper类
     * @param entity 实体类
     * @return 条数
     */
    <T extends Serializable> int insert(Class<?> mapperClass, T entity);
    /**新增,返回主键
     * @param mapperClass mapper类
     * @param entity 实体类
     * @return 条数
     */
    <T extends Serializable> int insertById(Class<?> mapperClass, T entity);
    /**查询条数
     * @param mapperClass mapper类
     * @param sqlSentence  查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int selectCount(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询条数
     * @param mapperClass mapper类
     * @param sqlSentence  查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int selectCountSql(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询列表,返回实体类的List
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回list
     */
    <T extends Serializable> List<T> selectList(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询列表,返回Map的List
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return Map的List
     */
    <T extends Serializable> List<Map<String,Object>> selectListMap(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询,返回单个实体
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回实体类
     */
    <T extends Serializable> T selectOne(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询,返回单个map
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回实体类
     */
    <T extends Serializable> Map<String,Object> selectOneMap(Class<?> mapperClass, SqlSentence sqlSentence);
    /**查询,返回实体类没有大数据的
     * @param mapperClass mapper类
     * @param object 数据标识key
     * @return 返回实体类
     */
    <T extends Serializable> T selectOneByKey(Class<?> mapperClass, Object object);
    /**查询,返回实体类有大数据的
     * @param mapperClass mapper类
     * @param object 数据标识key
     * @return 返回实体类
     */
    <T extends Serializable> T selectOneByKeyBlob(Class<?> mapperClass, Object object);
    /**更新,返回更新数量
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int updateWhere(Class<?> mapperClass, SqlSentence sqlSentence);
    /**更新,返回更新数量
     * @param mapperClass mapper类
     * @param entity 实体类
     * @return 返回条数
     */
    <T extends Serializable> int updateAll(Class<?> mapperClass, T entity);
    /**删除,返回删除数量
     * @param mapperClass mapper类
     * @param sqlSentence 查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int deleteWhere(Class<?> mapperClass, SqlSentence sqlSentence);
    /**删除,返回删除数量
     * @param mapperClass mapper类
     * @param object 数据标识key
     * @return 返回条数
     */
    <T extends Serializable> int deleteById(Class<?> mapperClass, Object object);
    /**更新sql语句(全语句)
     * @param sqlSentence 查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int updateSentence(SqlSentence sqlSentence);
    /**查询条数语句(全语句)
     * @param sqlSentence 查询参数类
     * @return 返回条数
     */
    <T extends Serializable> int selectCountSql(SqlSentence sqlSentence);
}
hx_common/src/main/java/com/hx/common/service/impl/CommonDaoImpl.java
New file
@@ -0,0 +1,123 @@
package com.hx.common.service.impl;
import com.hx.common.dao.CommonDao;
import com.hx.common.dao.mapper.CommonMapper;
import com.hx.mybatisTool.SqlSentence;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**当前是没有事务处理,切勿直接使用*/
@Service
public class CommonDaoImpl implements CommonDao {
    @Resource(name = "sqlSessionFactory")
    protected SqlSessionFactory sqlSessionFactory;
    /**组拼XML文件sql的id*/
    private <T> String getStatement(Class<T> clazz, String prefix){
        return clazz.getName()+"."+prefix;
    }
    /**插入*/
    @Override
    public <T extends Serializable> int insert(Class<?> mapperClass,T entity) {
        return sqlSessionFactory.openSession().insert(getStatement(mapperClass,"insert"),entity);
    }
    @Override
    public <T extends Serializable> int insertById(Class<?> mapperClass, T entity) {
        return sqlSessionFactory.openSession().insert(getStatement(mapperClass,"insertById"),entity);
    }
    /**获取条数
     * @return*/
    @Override
    public <T extends Serializable> int selectCount(Class<?> mapperClass, SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().selectOne(getStatement(mapperClass,"selectCount"),sqlSentence);
    }
    /**获取条数
     * @return*/
    @Override
    public <T extends Serializable> int selectCountSql(Class<?> mapperClass, SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().selectOne(getStatement(mapperClass,"selectCountSql"),sqlSentence);
    }
    /**获取列表*/
    @Override
    public <T extends Serializable> List<T> selectList(Class<?> mapperClass, SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().selectList(getStatement(mapperClass,"selectList"),sqlSentence);
    }
    /**获取列表*/
    @Override
    public <T extends Serializable> List<Map<String, Object>> selectListMap(Class<?> mapperClass, SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().selectList(getStatement(mapperClass,"selectListMap"),sqlSentence);
    }
    /**获取单条数据*/
    @Override
    public <T extends Serializable> T selectOne(Class<?> mapperClass, SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().selectOne(getStatement(mapperClass,"selectOne"),sqlSentence);
    }
    /**获取单条数据*/
    @Override
    public <T extends Serializable> Map<String, Object> selectOneMap(Class<?> mapperClass, SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().selectOne(getStatement(mapperClass,"selectOneMap"),sqlSentence);
    }
    /**获取单条数据-不含longText的数据*/
    @Override
    public <T extends Serializable> T selectOneByKey(Class<?> mapperClass,Object object) {
        return sqlSessionFactory.openSession().selectOne(getStatement(mapperClass,"selectOneByKey"),object);
    }
    /**获取单条数据-含longText的数据*/
    @Override
    public <T extends Serializable> T selectOneByKeyBlob(Class<?> mapperClass,Object object) {
        return sqlSessionFactory.openSession().selectOne(getStatement(mapperClass,"selectOneByKeyBlob"),object);
    }
    /**更新*/
    @Override
    public <T extends Serializable> int updateWhere(Class<?> mapperClass,SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().update(getStatement(mapperClass,"updateWhere"),sqlSentence);
    }
    /**全部字段更新*/
    @Override
    public <T extends Serializable> int updateAll(Class<?> mapperClass,T entity) {
        return sqlSessionFactory.openSession().update(getStatement(mapperClass,"updateAll"),entity);
    }
    /**删除*/
    @Override
    public <T extends Serializable> int deleteWhere(Class<?> mapperClass,SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().delete(getStatement(mapperClass,"deleteWhere"),sqlSentence);
    }
    /**删除*/
    @Override
    public <T extends Serializable> int deleteById(Class<?> mapperClass,Object object) {
        return sqlSessionFactory.openSession().delete(getStatement(mapperClass,"deleteById"),object);
    }
    /**更新sql语句(全语句)*/
    @Override
    public <T extends Serializable> int updateSentence(SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().update(getStatement(CommonMapper.class,"updateSentence"),sqlSentence);
    }
    /**查询条数(全语句)*/
    @Override
    public <T extends Serializable> int selectCountSql(SqlSentence sqlSentence) {
        return sqlSessionFactory.openSession().selectOne(getStatement(CommonMapper.class,"selectCountSql"),sqlSentence);
    }
}
hx_common/src/main/java/com/hx/common/service/impl/CommonServiceImpl.java
New file
@@ -0,0 +1,119 @@
package com.hx.common.service.impl;
import com.hx.common.dao.CommonDao;
import com.hx.common.service.CommonService;
import com.hx.mybatisTool.SqlSentence;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**当前是有事务处理*/
@Transactional
@Service
public class CommonServiceImpl implements CommonService {
    @Resource
    private CommonDao commonDao;
    /**插入*/
    @Override
    public <T extends Serializable> int insert(Class<?> mapperClass,T entity) {
        return commonDao.insert(mapperClass,entity);
    }
    @Override
    public <T extends Serializable> int insertById(Class<?> mapperClass, T entity) {
        return commonDao.insertById(mapperClass,entity);
    }
    /**获取条数*/
    @Override
    public <T extends Serializable> int selectCount(Class<?> mapperClass,SqlSentence sqlSentence) {
        return commonDao.selectCount(mapperClass,sqlSentence);
    }
    /**获取条数*/
    @Override
    public <T extends Serializable> int selectCountSql(Class<?> mapperClass,SqlSentence sqlSentence) {
        return commonDao.selectCountSql(mapperClass,sqlSentence);
    }
    /**获取列表*/
    @Override
    public <T extends Serializable> List<T> selectList(Class<?> mapperClass, SqlSentence sqlSentence) {
        return commonDao.selectList(mapperClass,sqlSentence);
    }
    /**获取列表*/
    @Override
    public <T extends Serializable> List<Map<String, Object>> selectListMap(Class<?> mapperClass, SqlSentence sqlSentence) {
        return commonDao.selectListMap(mapperClass,sqlSentence);
    }
    /**获取单条数据*/
    @Override
    public <T extends Serializable> T selectOne(Class<?> mapperClass, SqlSentence sqlSentence) {
        return commonDao.selectOne(mapperClass,sqlSentence);
    }
    /**获取单条数据*/
    @Override
    public <T extends Serializable> Map<String, Object> selectOneMap(Class<?> mapperClass, SqlSentence sqlSentence) {
        return commonDao.selectOneMap(mapperClass,sqlSentence);
    }
    /**获取单条数据-不含longText的数据*/
    @Override
    public <T extends Serializable> T selectOneByKey(Class<?> mapperClass,Object object) {
        return commonDao.selectOneByKey(mapperClass,object);
    }
    /**获取单条数据-含longText的数据*/
    @Override
    public <T extends Serializable> T selectOneByKeyBlob(Class<?> mapperClass,Object object) {
        return commonDao.selectOneByKeyBlob(mapperClass,object);
    }
    /**更新*/
    @Override
    public <T extends Serializable> int updateWhere(Class<?> mapperClass,SqlSentence sqlSentence) {
        return commonDao.updateWhere(mapperClass,sqlSentence);
    }
    /**全部字段更新*/
    @Override
    public <T extends Serializable> int updateAll(Class<?> mapperClass,T entity) {
        return commonDao.updateAll(mapperClass,entity);
    }
    /**删除*/
    @Override
    public <T extends Serializable> int deleteWhere(Class<?> mapperClass,SqlSentence sqlSentence) {
        return commonDao.deleteWhere(mapperClass,sqlSentence);
    }
    /**删除*/
    @Override
    public <T extends Serializable> int deleteById(Class<?> mapperClass,Object object) {
        return commonDao.deleteById(mapperClass,object);
    }
    /**更新sql语句(全语句)*/
    @Override
    public <T extends Serializable> int updateSentence(SqlSentence sqlSentence) {
        return commonDao.updateSentence(sqlSentence);
    }
    /**更新sql语句(全语句)*/
    @Override
    public <T extends Serializable> int selectCountSql(SqlSentence sqlSentence) {
        return commonDao.selectCountSql(sqlSentence);
    }
}
hx_common/src/main/java/com/hx/common/xml/CommonMapper.xml
New file
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:该mapper.xml映射文件的 唯一标识 -->
<mapper namespace="com.hx.common.dao.mapper.CommonMapper">
    <update id="updateSentence" parameterType="com.hx.mybatisTool.SqlSentence" >
         ${sqlSentence}
    </update>
    <select id="selectListMap" resultType="java.util.Map" parameterType="com.hx.mybatisTool.SqlSentence" >
        ${sqlSentence}
    </select>
    <select id="selectCountSql" resultType="int" parameterType="com.hx.mybatisTool.SqlSentence" >
        ${sqlSentence}
    </select>
</mapper>
hx_common/src/main/java/com/hx/corp/entity/CorpPayRequest.java
New file
@@ -0,0 +1,135 @@
package com.hx.corp.entity;
import java.util.UUID;
/**企业付款请求参数实体
 *
 */
public class CorpPayRequest {
    /*(Y)商户账号appid,申请商户号的appid或商户号绑定的appid*/
    private String mch_appid;
    /*(Y)商户号*/
    private String mchid;
    /*(N)设备号*/
    private String device_info;
    /*(Y)随机字符串*/
    private String nonce_str = UUID.randomUUID().toString().substring(0, 30);
    /*(Y)随签名*/
    private String sign;
    /*(Y)商户订单号*/
    private String partner_trade_no;
    /*(Y)用户openid*/
    private String openid;
    /*(Y)校验用户姓名选项,NO_CHECK:不校验真实姓名 ;FORCE_CHECK:强校验真实姓名*/
    private String check_name = "NO_CHECK";
    /*(O)收款用户姓名,如果check_name设置为FORCE_CHECK,则必填用户真实姓名*/
    private String re_user_name;
    /*(Y)金额*/
    private Integer amount;
    /*(Y)企业付款备注*/
    private String desc;
    /*(N)Ip地址,该IP同在商户平台设置的IP白名单中的IP没有关联,该IP可传用户端或者服务端的IP*/
    private String spbill_create_ip = "8.8.8.8";
    public CorpPayRequest() {
    }
    ////////////////////////////////////////////////////////
    public String getMch_appid() {
        return mch_appid;
    }
    public void setMch_appid(String mch_appid) {
        this.mch_appid = mch_appid;
    }
    public String getMchid() {
        return mchid;
    }
    public void setMchid(String mchid) {
        this.mchid = mchid;
    }
    public String getDevice_info() {
        return device_info;
    }
    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getPartner_trade_no() {
        return partner_trade_no;
    }
    public void setPartner_trade_no(String partner_trade_no) {
        this.partner_trade_no = partner_trade_no;
    }
    public String getOpenid() {
        return openid;
    }
    public void setOpenid(String openid) {
        this.openid = openid;
    }
    public String getCheck_name() {
        return check_name;
    }
    public void setCheck_name(String check_name) {
        this.check_name = check_name;
    }
    public String getRe_user_name() {
        return re_user_name;
    }
    public void setRe_user_name(String re_user_name) {
        this.re_user_name = re_user_name;
    }
    public Integer getAmount() {
        return amount;
    }
    public void setAmount(Integer amount) {
        this.amount = amount;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    public String getSpbill_create_ip() {
        return spbill_create_ip;
    }
    public void setSpbill_create_ip(String spbill_create_ip) {
        this.spbill_create_ip = spbill_create_ip;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
}
hx_common/src/main/java/com/hx/corp/entity/CorpPayResponse.java
New file
@@ -0,0 +1,157 @@
package com.hx.corp.entity;
/**企业付款返回参数实体
 *
 */
public class CorpPayResponse {
    /*(Y)业务结果,SUCCESS/FAIL,注意:当状态为FAIL时,存在业务结果未明确的情况。如果状态为FAIL,请务必关注错误代码(err_code字段),通过查询接口确认此次付款的结果*/
    private String result_code = "FAIL";
    /*(Y)返回状态码,SUCCESS/FAIL,此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断*/
    private String return_code = "FAIL";
    /*(Y) 返回信息 */
    private String return_msg;
    /*(Y)错误代码*/
    private String err_code;
    /*(Y)错误代码描述*/
    private String err_code_des;
    /*(Y)商户appid*/
    private String mch_appid;
    /*(Y)商户号*/
    private String mchid;
    /*(N)设备号*/
    private String device_info;
    /*(Y)随机字符串*/
    private String nonce_str;
    //以下字段在return_code 和result_code都为SUCCESS的时候有返回
    /*(O)商户订单号*/
    private String partner_trade_no;
    /*(O)商户订单号*/
    private String payment_no;
    /*(O)付款成功时间*/
    private String payment_time;
    public CorpPayResponse() {
    }
    public static final String CODE_SUC = "SUCCESS";
    public static final String CODE_FAIL = "FAIL";
    ////////////////////////////////////////////////////////
    public String getMch_appid() {
        return mch_appid;
    }
    public void setMch_appid(String mch_appid) {
        this.mch_appid = mch_appid;
    }
    public String getMchid() {
        return mchid;
    }
    public void setMchid(String mchid) {
        this.mchid = mchid;
    }
    public String getDevice_info() {
        return device_info;
    }
    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }
    public String getResult_code() {
        return result_code;
    }
    public void setResult_code(String result_code) {
        this.result_code = result_code;
    }
    public String getErr_code() {
        return err_code;
    }
    public void setErr_code(String err_code) {
        this.err_code = err_code;
    }
    public String getErr_code_des() {
        return err_code_des;
    }
    public void setErr_code_des(String err_code_des) {
        this.err_code_des = err_code_des;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getPartner_trade_no() {
        return partner_trade_no;
    }
    public void setPartner_trade_no(String partner_trade_no) {
        this.partner_trade_no = partner_trade_no;
    }
    public String getPayment_no() {
        return payment_no;
    }
    public void setPayment_no(String payment_no) {
        this.payment_no = payment_no;
    }
    public String getPayment_time() {
        return payment_time;
    }
    public void setPayment_time(String payment_time) {
        this.payment_time = payment_time;
    }
    public String getReturn_code() {
        return return_code;
    }
    public void setReturn_code(String return_code) {
        this.return_code = return_code;
    }
    public String getReturn_msg() {
        return return_msg;
    }
    public void setReturn_msg(String return_msg) {
        this.return_msg = return_msg;
    }
    @Override
    public String toString() {
        return "CorpPayResponse{" +
                "result_code='" + result_code + '\'' +
                ", return_code='" + return_code + '\'' +
                ", return_msg='" + return_msg + '\'' +
                ", err_code='" + err_code + '\'' +
                ", err_code_des='" + err_code_des + '\'' +
                ", mch_appid='" + mch_appid + '\'' +
                ", mchid='" + mchid + '\'' +
                ", device_info='" + device_info + '\'' +
                ", nonce_str='" + nonce_str + '\'' +
                ", partner_trade_no='" + partner_trade_no + '\'' +
                ", payment_no='" + payment_no + '\'' +
                ", payment_time='" + payment_time + '\'' +
                '}';
    }
}
hx_common/src/main/java/com/hx/corp/util/WxCorpPayUtil.java
New file
@@ -0,0 +1,613 @@
package com.hx.corp.util;
import com.alibaba.fastjson.JSON;
import com.hx.util.corp.entity.AppLetInfo;
import com.hx.corp.entity.CorpPayRequest;
import com.hx.corp.entity.CorpPayResponse;
import com.hx.exception.ServiceException;
import com.hx.mp.util.*;
import com.hx.util.HttpMethodUtil;
import com.hx.util.SimpleTool;
import com.hx.util.StringUtils;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.*;
/** 企业微信支付/退款
 * @author ChenJiaHe
 */
public class WxCorpPayUtil {
    //log4j日志
    private static Logger logger = LoggerFactory.getLogger(WxCorpPayUtil.class.getName());
    // 退款接口连接
    private static final String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
     /**查询订单链接*/
    @SuppressWarnings("unused")
    private static final String QUERY_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
    /**同意下单链接*/
    private static final String FIRST_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    // 企业付款
    private static final String CORP_PAY_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
    /** 企业付款
     * @param corpPayRequest 请求对象
     * @param mchKey 商户号秘钥
     * @param certPath 支付证书
     * @return CorpPayResponse
     * @throws Exception
     */
    public static CorpPayResponse qdCorpPay(CorpPayRequest corpPayRequest, String mchKey, String certPath)
            throws Exception {
        CorpPayResponse corpPayResponse = new CorpPayResponse();
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("mch_appid", corpPayRequest.getMch_appid());
        parameters.put("mchid", corpPayRequest.getMchid());
        parameters.put("partner_trade_no", corpPayRequest.getPartner_trade_no());
        //parameters.put("nonce_str", UUID.randomUUID().toString().substring(0, 30));
        parameters.put("nonce_str", corpPayRequest.getNonce_str());
        parameters.put("openid", corpPayRequest.getOpenid());
        parameters.put("check_name", corpPayRequest.getCheck_name());
        parameters.put("amount", corpPayRequest.getAmount().toString());
        parameters.put("spbill_create_ip", corpPayRequest.getSpbill_create_ip());
        parameters.put("desc", corpPayRequest.getDesc());
        corpPayRequest.setSign(WXSignUtils.createSign("UTF-8", parameters, mchKey));
        parameters.put("sign", corpPayRequest.getSign());
        String xmlInfo = HttpXmlUtils.transferXml(parameters);
        try {
            CloseableHttpResponse response = HttpUtil.Post(CORP_PAY_URL, xmlInfo, true, certPath, corpPayRequest.getMchid());
            String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
           //Map<String, String> transferMap = HttpXmlUtils.parseRefundXml(transfersXml);
            Map<String,Object> transferMap = XMLUtil.doXMLParse(transfersXml);
            // 将 Map 转换为 实体类
            corpPayResponse = JSON.parseObject(JSON.toJSONString(transferMap),CorpPayResponse.class);
        } catch (Exception e) {
            logger.error("企业付款接口报错",e);
        }
        return corpPayResponse;
    }
    /**统一支付
     * @param request 方法获取
     * @param appId  小程序号
     * @param partner  商户号
     * @param key  秘钥
     * @param notifyUrl  回调链接
     * @param out_trade_no  订单号
     * @param body 商品描述
     * @param total_fee 支付金额
     * @param openid 用户openId
     * @param attach 附带数据包
     * @param notifyUrl 回调通知地址
     * @param trade_type 交易类型
     * @return JSON  status = "SUC"为成功
     */
    public static JSONObject unifiedPay(HttpServletRequest request,String appId,String partner,String key,String notifyUrl,String out_trade_no, String body, String total_fee, String openid,
            String attach,String trade_type) throws Exception {
        if (!SimpleTool.checkNotNull(notifyUrl)) {
            throw new ServiceException("支付功能故障!");
        }
        // 创建查询请求对象
        RequestHandler reqHandler = new RequestHandler(null, null);
        // 通信对象
        TenpayHttpClient httpClient = new TenpayHttpClient();
        // 应答对象
        ClientResponseHandler resHandler = new ClientResponseHandler();
        // -----------------------------
        // 设置请求参数
        // -----------------------------
        // reqHandler.init();
        reqHandler.setKey(key);
        reqHandler.setGateUrl(FIRST_ORDER_URL);// 请求URL
        // -----------------------------
        // 设置接口参数(sign后台自动生成)
        // -----------------------------
        reqHandler.setParameter("appid", appId); // 公众号/小程序
        reqHandler.setParameter("mch_id", partner); // 商户号
        reqHandler.setParameter("nonce_str", SimpleTool.getUUIDName().substring(0, 30));// 随机乱码
        reqHandler.setParameter("body", body);// 商品描述
        reqHandler.setParameter("out_trade_no", out_trade_no);// 商户订单号
        reqHandler.setParameter("total_fee", total_fee);// 总金额
        reqHandler.setParameter("spbill_create_ip", "8.8.8.8");// 终端IP
        reqHandler.setParameter("notify_url",notifyUrl);// 通知地址
        reqHandler.setParameter("trade_type", trade_type);// 交易类型
                                                          // JSAPI,NATIVE,APP
        reqHandler.setParameter("openid", openid);// openId
        reqHandler.setParameter("attach", attach);// 附带数据包
        // -----------------------------
        // 设置通信参数
        // -----------------------------
        // 设置请求返回的等待时间
        httpClient.setTimeOut(5);
        // 设置ca证书
        // httpClient.setCaInfo(new File(CA_PATH));
        // 设置个人(商户)证书
        // httpClient.setCertInfo(new File(CERT_PATH), CERT_PWD);
        // 设置发送类型POST
        httpClient.setMethod("POST");
        // 设置请求内容(生成sign)
        String requestUrl = reqHandler.getRequestURL();// 组拼https://www.baidu.com?a=x&b=xx
        httpClient.setReqContent(requestUrl);// https://www.baidu.com?a=x&b=xx
        String rescontent = "null";
        httpClient.setRequestHandler(reqHandler);// 把处理对象,像是参数各种东西都设置进去方便获取(quan)
        // 返回出去的对象(状态,错误原因,该操作相关信息(参数,返回值))
        JSONObject returnObj = new JSONObject();
        // 后台调用
        if (httpClient.call()) {
            System.out.println("统一下单,成功cll了::");
            // 设置结果参数
            rescontent = httpClient.getResContent();
            System.out.println("统一下单返回结果:" + rescontent);
            resHandler.setContent(rescontent);// 解析xml
            resHandler.setKey(key);
            // 获取返回参数
            String return_code = resHandler.getParameter("return_code");
            String return_msg = resHandler.getParameter("return_msg");
            // 判断签名及结果
            if (resHandler.isTenpaySign() && "SUCCESS".equals(return_code)) {
                String prepay_id = resHandler.getParameter("prepay_id");// 预支付交易会话标识
                String code_url = resHandler.getParameter("code_url");// 二维码链接
                String result_code = resHandler.getParameter("result_code");// 业务结果
                String appid = resHandler.getParameter("appid");// 公众账号ID
                String mch_id = resHandler.getParameter("mch_id");// 商户号
                String nonce_str = resHandler.getParameter("nonce_str");// 随机码
                String sign = resHandler.getParameter("sign");// 签名
                if (result_code.equals("SUCCESS")) {
                    returnObj.put("status", "suc");
                    returnObj.put("sign", sign);
                    returnObj.put("nonce_str", nonce_str);
                    returnObj.put("mch_id", mch_id);
                    returnObj.put("appid", appid);
                    returnObj.put("prepay_id", prepay_id);
                    returnObj.put("code_url", code_url);
                    returnObj.put("out_trade_no", out_trade_no);
                } else {
                    String errMsg = "[ERROR]result_code:" + resHandler.getParameter("result_code") + " err_code:"
                            + resHandler.getParameter("err_code") + "err_code_des:"
                            + resHandler.getParameter("err_code_des");
                    // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                    returnObj.put("status", "ERROR-C");
                    returnObj.put("errMsg", errMsg);
                }
            } else {
                String errMsg = "return_code:" + return_code + "err_code:" + resHandler.getParameter("err_code")
                        + " return_msg:" + return_msg;
                // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                returnObj.put("status", "ERROR-B");
                returnObj.put("errMsg", errMsg);
            }
        } else {
            // 有可能因为网络原因,请求已经处理,但未收到应答。
            returnObj.put("status", "ERROR-A");
            returnObj.put("errMsg", httpClient.getResponseCode() + ":" + httpClient.getErrInfo());
        }
        // 获取debug信息,建议把请求、应答内容、debug信息,通信返回码写入日志,方便定位问题
        String detail = "http res:" + httpClient.getResponseCode() + "," + httpClient.getErrInfo() + ";" + "req url:"
                + requestUrl + ";" + ";" + "req debug:" + reqHandler.getDebugInfo() + ";" + "res content:" + rescontent
                + ";" + "res debug:" + resHandler.getDebugInfo() + ";";
        returnObj.put("detail", detail);
        return returnObj;
    }
    /**统一支付(分账)
     * @param request 方法获取
     * @param appId  小程序号
     * @param partner  商户号
     * @param key  秘钥
     * @param notifyUrl  回调链接
     * @param out_trade_no  订单号
     * @param body 商品描述
     * @param total_fee 支付金额
     * @param openid 用户openId
     * @param attach 附带数据包
     * @param notifyUrl 回调通知地址
     * @param trade_type 交易类型
     * @param profit_sharing 是否分账:N不,Y是
     * @return JSON  status = "SUC"为成功
     */
    public static JSONObject unifiedPay(HttpServletRequest request,String appId,String partner,String key,String notifyUrl,String out_trade_no, String body, String total_fee, String openid,
                                        String attach,String trade_type,String profit_sharing) throws Exception {
        if (!SimpleTool.checkNotNull(notifyUrl)) {
            throw new ServiceException("支付功能故障!");
        }
        // 创建查询请求对象
        RequestHandler reqHandler = new RequestHandler(null, null);
        // 通信对象
        TenpayHttpClient httpClient = new TenpayHttpClient();
        // 应答对象
        ClientResponseHandler resHandler = new ClientResponseHandler();
        // -----------------------------
        // 设置请求参数
        // -----------------------------
        // reqHandler.init();
        reqHandler.setKey(key);
        reqHandler.setGateUrl(FIRST_ORDER_URL);// 请求URL
        // -----------------------------
        // 设置接口参数(sign后台自动生成)
        // -----------------------------
        reqHandler.setParameter("appid", appId); // 公众号/小程序
        reqHandler.setParameter("mch_id", partner); // 商户号
        reqHandler.setParameter("nonce_str", SimpleTool.getUUIDName().substring(0, 30));// 随机乱码
        reqHandler.setParameter("body", body);// 商品描述
        reqHandler.setParameter("out_trade_no", out_trade_no);// 商户订单号
        reqHandler.setParameter("total_fee", total_fee);// 总金额
        reqHandler.setParameter("spbill_create_ip", "8.8.8.8");// 终端IP
        reqHandler.setParameter("notify_url",notifyUrl);// 通知地址
        reqHandler.setParameter("trade_type", trade_type);// 交易类型
        //JSAPI,NATIVE,APP
        reqHandler.setParameter("openid", openid);// openId
        reqHandler.setParameter("attach", attach);// 附带数据包
        reqHandler.setParameter("profit_sharing", profit_sharing);// 附带数据包
        // -----------------------------
        // 设置通信参数
        // -----------------------------
        // 设置请求返回的等待时间
        httpClient.setTimeOut(5);
        // 设置ca证书
        // httpClient.setCaInfo(new File(CA_PATH));
        // 设置个人(商户)证书
        // httpClient.setCertInfo(new File(CERT_PATH), CERT_PWD);
        // 设置发送类型POST
        httpClient.setMethod("POST");
        // 设置请求内容(生成sign)
        String requestUrl = reqHandler.getRequestURL();// 组拼https://www.baidu.com?a=x&b=xx
        httpClient.setReqContent(requestUrl);// https://www.baidu.com?a=x&b=xx
        String rescontent = "null";
        httpClient.setRequestHandler(reqHandler);// 把处理对象,像是参数各种东西都设置进去方便获取(quan)
        // 返回出去的对象(状态,错误原因,该操作相关信息(参数,返回值))
        JSONObject returnObj = new JSONObject();
        // 后台调用
        if (httpClient.call()) {
            System.out.println("统一下单,成功cll了::");
            // 设置结果参数
            rescontent = httpClient.getResContent();
            System.out.println("统一下单返回结果:" + rescontent);
            resHandler.setContent(rescontent);// 解析xml
            resHandler.setKey(key);
            // 获取返回参数
            String return_code = resHandler.getParameter("return_code");
            String return_msg = resHandler.getParameter("return_msg");
            // 判断签名及结果
            if (resHandler.isTenpaySign() && "SUCCESS".equals(return_code)) {
                String prepay_id = resHandler.getParameter("prepay_id");// 预支付交易会话标识
                String code_url = resHandler.getParameter("code_url");// 二维码链接
                String result_code = resHandler.getParameter("result_code");// 业务结果
                String appid = resHandler.getParameter("appid");// 公众账号ID
                String mch_id = resHandler.getParameter("mch_id");// 商户号
                String nonce_str = resHandler.getParameter("nonce_str");// 随机码
                String sign = resHandler.getParameter("sign");// 签名
                if (result_code.equals("SUCCESS")) {
                    returnObj.put("status", "suc");
                    returnObj.put("sign", sign);
                    returnObj.put("nonce_str", nonce_str);
                    returnObj.put("mch_id", mch_id);
                    returnObj.put("appid", appid);
                    returnObj.put("prepay_id", prepay_id);
                    returnObj.put("code_url", code_url);
                    returnObj.put("out_trade_no", out_trade_no);
                } else {
                    String errMsg = "[ERROR]result_code:" + resHandler.getParameter("result_code") + " err_code:"
                            + resHandler.getParameter("err_code") + "err_code_des:"
                            + resHandler.getParameter("err_code_des");
                    // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                    returnObj.put("status", "ERROR-C");
                    returnObj.put("errMsg", errMsg);
                }
            } else {
                String errMsg = "return_code:" + return_code + "err_code:" + resHandler.getParameter("err_code")
                        + " return_msg:" + return_msg;
                // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                returnObj.put("status", "ERROR-B");
                returnObj.put("errMsg", errMsg);
            }
        } else {
            // 有可能因为网络原因,请求已经处理,但未收到应答。
            returnObj.put("status", "ERROR-A");
            returnObj.put("errMsg", httpClient.getResponseCode() + ":" + httpClient.getErrInfo());
        }
        // 获取debug信息,建议把请求、应答内容、debug信息,通信返回码写入日志,方便定位问题
        String detail = "http res:" + httpClient.getResponseCode() + "," + httpClient.getErrInfo() + ";" + "req url:"
                + requestUrl + ";" + ";" + "req debug:" + reqHandler.getDebugInfo() + ";" + "res content:" + rescontent
                + ";" + "res debug:" + resHandler.getDebugInfo() + ";";
        returnObj.put("detail", detail);
        return returnObj;
    }
    /**处理信息
     */
    public static JSONObject paymentData(JSONObject payObj,String key){
        JSONObject wxObj = new JSONObject();
        /**统一下单*/
        String payStatus = payObj.getString("status");
        if (payStatus.equals("suc")) {
            // JSONObject payObj = po.getJSONObject("inf");
            String appId = payObj.getString("appid");
            String nonceStr = payObj.getString("nonce_str");
            String prepay_id = payObj.getString("prepay_id");
            // JSAPI调用支付返回的数据
            String timeStamp = SimpleTool.getTenTime(new Date()).toString();
            String signType = "MD5";
            String packagef = "prepay_id=" + prepay_id;
            RequestHandler reqHandler = new RequestHandler(null, null);
            reqHandler.setParameter("appId", appId);
            reqHandler.setParameter("nonceStr", nonceStr);
            reqHandler.setParameter("timeStamp", timeStamp);
            reqHandler.setParameter("package", packagef);
            reqHandler.setParameter("signType", signType);
            reqHandler.setKey(key);
            String paySign = reqHandler.createSign();// 生成签名
            wxObj.put("orderNo", payObj.getString("out_trade_no"));
            wxObj.put("paySign", paySign);
            wxObj.put("appId", appId);
            wxObj.put("nonceStr", nonceStr);
            wxObj.put("package", packagef);
            wxObj.put("timeStamp", timeStamp);
        } else {
            throw new RuntimeException(payObj.toString());
        }
        return wxObj;
    }
    /**
     * 退款
     * @param appId 小程序/公众号 appId
     * @param partner 商户号
     * @param key 商户号秘钥
     * @param certPath 个人商户证书
     * @param out_trade_no 商户订单号
     * @param transaction_id 财付通订单号(微信订单号)
     * @param out_refund_no 商户退单号
     * @param total_fee 订单总额(单位:分)
     * @param refund_fee 退款金额(单位:分)
     * @return JSON status="SUCCESS"(成功) (状态,错误原因,该操作相关信息(参数,返回值))
     */
    public static JSONObject refund(String appId,String partner,String key,String certPath,String out_trade_no, String transaction_id, String out_refund_no, String total_fee,
            String refund_fee) {
         try{
             KeyStore keyStore = KeyStore.getInstance("PKCS12");
             FileInputStream instream = new FileInputStream(new File(certPath));
             try {
                 keyStore.load(instream,partner.toCharArray());
             }finally {
                 instream.close();
             }
             // Trust own CA and all self-signed certs
             SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,partner.toCharArray()).build();
             // Allow TLSv1 protocol only
             SSLConnectionSocketFactory sslsf;
            sslsf = new SSLConnectionSocketFactory(
                    sslcontext, new String[] { "TLSv1" }, null,
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                     .setSSLSocketFactory(sslsf).build();
             HttpPost httppost = new HttpPost(REFUND_URL);
             String xml = wxPayRefundData(appId, partner, key, out_trade_no, transaction_id, out_refund_no, total_fee, refund_fee);
             try {
                 StringEntity se = new StringEntity(xml);
                 httppost.setEntity(se);
                 CloseableHttpResponse responseEntry = httpclient.execute(httppost);
                 try {
                     HttpEntity entity = responseEntry.getEntity();
                     if (entity != null) {
                         SAXReader saxReader = new SAXReader();
                         Document document = saxReader.read(entity.getContent());
                         Element rootElt = document.getRootElement();
                         String returnCode = rootElt.elementText("return_code");
                         JSONObject result = new JSONObject();
                         if(returnCode.equals("SUCCESS")){
                             String resultCode = rootElt.elementText("result_code");
                             if(resultCode.equals("SUCCESS")) {
                                 result.put("weixinPayUrl", rootElt.elementText("code_url"));
                                 result.put("prepayId", rootElt.elementText("prepay_id"));
                                 result.put("msg", "success");
                                 String refund_id = rootElt.elementText("refund_id");//微信退款单号
                                 String r_out_refund_no = rootElt.elementText("out_refund_no");
                                 String errMsg = "商户号" + r_out_refund_no + "的退款流水号是:" + refund_id;
                                 result.put("status", "SUCCESS");
                                 result.put("errMsg", errMsg);
                                 result.put("refund_id", refund_id);
                             }else{
                                 String errMsg = "[ERROR]result_code:" + rootElt.elementText("result_code")+
                                         " err_code:" + rootElt.elementText("err_code");
                                 //错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                                 result.put("errMsg", errMsg);
                                 result.put("status","false");
                                 result.put("msg",rootElt.elementText("err_code_des"));
                             }
                         }else{
                             String errMsg = "[ERROR]return_code:" + rootElt.elementText("return_code");
                             //错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                             result.put("errMsg", errMsg);
                             result.put("status","false");
                             result.put("msg",rootElt.elementText("return_msg"));
                         }
                         return result;
                     }
                     EntityUtils.consume(entity);
                 }
                 finally {
                     responseEntry.close();
                 }
             }
             finally {
                 httpclient.close();
             }
             return null;
         }catch(Exception e){
             e.printStackTrace();
             JSONObject result = new JSONObject();
             result.put("status","error");
             result.put("msg",e.getMessage());
             return result;
         }
    }
    /** 封装参数数据
     * @param appId 小程序/公众号 appId
     * @param partner 商户号
     * @param key 商户号秘钥
     * @param out_trade_no 商户订单号
     * @param transaction_id 财付通订单号(微信订单号)
     * @param out_refund_no 商户退单号
     * @param total_fee 订单总额(单位:分)
     * @param refund_fee 退款金额(单位:分)
     * @return
     */
    public static String wxPayRefundData(String appId,String partner,String key,String out_trade_no, String transaction_id,String out_refund_no,String total_fee,String refund_fee) {
        StringBuffer xml = new StringBuffer();
        String data = null;
        try {
            String nonceStr = SimpleTool.getUUIDName().substring(0,30);
            xml.append("</xml>");
            SortedMap<String,String> parameters = new TreeMap<String,String>();
            parameters.put("appid",appId);
            parameters.put("mch_id",partner);
            parameters.put("nonce_str", nonceStr);
            if(!StringUtils.isEmpty(out_trade_no)) {
                parameters.put("out_trade_no", out_trade_no);
            }
            if(!StringUtils.isEmpty(transaction_id)) {
                parameters.put("transaction_id", transaction_id);
            }
            parameters.put("out_refund_no", out_refund_no);
            parameters.put("fee_type", "CNY");
            parameters.put("total_fee", total_fee);//总金额
            parameters.put("refund_fee", refund_fee);//退款金额
            parameters.put("op_user_id",partner);
            parameters.put("sign", createSign(parameters,key));
            data =SortedMaptoXml(parameters);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            return null;
        }
        return data;
    }
    /**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     */
    public static String createSign(SortedMap<String, String> packageParams, String AppKey) {
        StringBuffer sb;
        sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + AppKey);
        String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
        return sign;
    }
    /**
     * @Author: HONGLINCHEN
     * @Description:请求值转换为xml格式 SortedMap转xml
     * @param params
     * @Date: 2017-9-7 17:18
     */
    private static String SortedMaptoXml(SortedMap<String,String> params) {
        StringBuilder sb = new StringBuilder();
        Set es = params.entrySet();
        Iterator it = es.iterator();
        sb.append("<xml>\n");
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            sb.append("<"+k+">");
            sb.append(v);
            sb.append("</"+k+">\n");
        }
        sb.append("</xml>");
        return sb.toString();
    }
}
hx_common/src/main/java/com/hx/encryption/PTConstant.java
New file
@@ -0,0 +1,34 @@
package com.hx.encryption;
/**
 *  接口解密返回结果配置
 * @author wangrenhuang
 * @Data 2020-06-09
 */
public class PTConstant {
    public static String PT_SIGN_EEMPLY = "签名为空!";
    public static String PT_TIMELS_EMPLY = "时间为空!";
    public static String PT_SIGN_ERROR = "签名错误";
    public static String PT_ORER_TIME = "接口超时";
    private boolean success;
    private String errCode;
    /*************************************************************************/
    public boolean isSuccess() {
        return success;
    }
    public void setSuccess(boolean success) {
        this.success = success;
    }
    public String getErrCode() {
        return errCode;
    }
    public void setErrCode(String errCode) {
        this.errCode = errCode;
    }
}
hx_common/src/main/java/com/hx/encryption/PTEncryptionUtil.java
New file
@@ -0,0 +1,76 @@
package com.hx.encryption;
import com.hx.util.DateUtil;
import com.hx.util.MD5Util;
import com.hx.util.StringUtils;
import java.util.Calendar;
import java.util.Date;
/*
 * @Description: his助手调用 phitab 订单加密工具
 * @Author: wangrenhuang
 * @Date:  2022/2/15-11:20
 */
public class PTEncryptionUtil {
    /*
     * 日期加密
     * date  要加密的日期
     * */
    public static String  encryption(Date date){
        Calendar cal=Calendar.getInstance();
        cal.setTime(date);
        StringBuffer data = new StringBuffer();
        data.append(cal.get(Calendar.DATE));
        data.append(cal.get(Calendar.MONTH));
        data.append(cal.get(Calendar.YEAR));
        data.append(cal.get(Calendar.SECOND));
        data.append(cal.get(Calendar.MINUTE));
        data.append(cal.get(Calendar.HOUR_OF_DAY));
        return com.hx.mp.util.MD5Util.MD5Encode(data.toString(),"");
    }
    /**
     *
     * @param data 签名
     * @param date 时间
     * @param time 有效时间 秒
     * @return
     */
    public static PTConstant decode(String data,Date date,Integer time){
        PTConstant ptConstant = new PTConstant();
        ptConstant.setSuccess(true);
        if (StringUtils.isEmpty(data)){
            ptConstant.setSuccess(false);
            ptConstant.setErrCode(PTConstant.PT_SIGN_EEMPLY);
            return ptConstant;
        }
        if (null == date){
            ptConstant.setSuccess(false);
            ptConstant.setErrCode(PTConstant.PT_TIMELS_EMPLY);
            return ptConstant;
        }
        if(!encryption(date).equals(data)){
            ptConstant.setSuccess(false);
            ptConstant.setErrCode(PTConstant.PT_SIGN_ERROR);
            return ptConstant;
        }
        if(time == null){
            ptConstant.setSuccess(true);
            return ptConstant;
        }
        //有效时间判断
        if (DateUtil.calLastedTime(date) > time){
            ptConstant.setSuccess(false);
            ptConstant.setErrCode(PTConstant.PT_ORER_TIME);
            return ptConstant;
        }
        return ptConstant;
    }
}
hx_common/src/main/java/com/hx/exception/LoginException.java
New file
@@ -0,0 +1,35 @@
package com.hx.exception;
/**
 * 登录提示异常
 * @author ChenJiaHe
 * @Date 2020-11-17
 */
public class LoginException extends RuntimeException {
    private Integer code;
    public LoginException(String message) {
        super(message);
    }
    public LoginException(String message, Integer code) {
        super(message);
        this.code = code;
    }
    public LoginException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }
    public LoginException(Throwable cause, Integer code) {
        super(cause);
        this.code = code;
    }
    //@Override
    public int getCode() {
        return this.code;
    }
}
hx_common/src/main/java/com/hx/exception/ParamException.java
New file
@@ -0,0 +1,12 @@
package com.hx.exception;
/** 参数异常
 * @author ChenJiaHe
 * @Date 2020-06-19
 */
public class ParamException extends RuntimeException {
    public ParamException(String message) {
        super(message);
    }
}
hx_common/src/main/java/com/hx/exception/ServiceException.java
New file
@@ -0,0 +1,37 @@
package com.hx.exception;
/** 判断异常/业务异常
 * @author ChenJiaHe
 * @Date 2020-06-19
 */
public class ServiceException extends RuntimeException {
    private Integer code;
    public ServiceException(String message) {
        super(message);
    }
    public ServiceException(String message, Integer code) {
        super(message);
        this.code = code;
    }
    public ServiceException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }
    public ServiceException(Throwable cause, Integer code) {
        super(cause);
        this.code = code;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
}
hx_common/src/main/java/com/hx/exception/TipsException.java
New file
@@ -0,0 +1,38 @@
package com.hx.exception;
/**
 * 前端提示异常
 * @author ChenJiaHe
 * @Date 2020-06-19
 */
public class TipsException extends RuntimeException {
    private Integer code;
    public TipsException(String message) {
        super(message);
    }
    public TipsException(String message, Integer code) {
        super(message);
        this.code = code;
    }
    public TipsException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }
    public TipsException(Throwable cause, Integer code) {
        super(cause);
        this.code = code;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
}
hx_common/src/main/java/com/hx/mp/util/CertUtil.java
New file
@@ -0,0 +1,31 @@
package com.hx.mp.util;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
@SuppressWarnings("deprecation")
public class CertUtil {
    /**
     * 加载证书
     */
    public static SSLConnectionSocketFactory initCert(String certPath, String mchId) throws Exception {
        FileInputStream instream = null;
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        instream = new FileInputStream(new File(certPath));
        keyStore.load(instream, mchId.toCharArray());
        if (null != instream) {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,mchId.toCharArray()).build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        return sslsf;
    }
}
hx_common/src/main/java/com/hx/mp/util/ClientResponseHandler.java
New file
@@ -0,0 +1,228 @@
package com.hx.mp.util;
import org.jdom.JDOMException;
import java.io.IOException;
import java.util.*;
/**
 * ��̨Ӧ����<br/>
 * ========================================================================<br/>
 * api˵����<br/>
 * getKey()/setKey(),��ȡ/������Կ<br/>
 * getContent() / setContent(), ��ȡ/����ԭʼ����<br/>
 * getParameter()/setParameter(),��ȡ/���ò���ֵ<br/>
 * getAllParameters(),��ȡ���в���<br/>
 * isTenpaySign(),�Ƿ�Ƹ�ͨǩ��,true:�� false:��<br/>
 * getDebugInfo(),��ȡdebug��Ϣ<br/>
 *
 * ========================================================================<br/>
 *
 */
public class ClientResponseHandler {
    /** Ӧ��ԭʼ���� */
    private String content;
    /** Ӧ��IJ��� */
    @SuppressWarnings("rawtypes")
    private SortedMap parameters;
    /** debug��Ϣ */
    private String debugInfo;
    /** ��Կ */
    private String key;
    /** �ַ� */
    private String charset;
    /*@SuppressWarnings("rawtypes")
    public ClientResponseHandler() {
        this.content = "";
        this.parameters = new TreeMap();
        this.debugInfo = "";
        this.key = "";
        this.charset = "UTF-8";
    }*/
    public ClientResponseHandler() {
        this.content = "";
        this.parameters = new TreeMap();
        this.debugInfo = "";
        this.key = "";
        this.charset = "UTF-8";
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) throws Exception {
        this.content = content;
        this.doParse();
    }
    /**
     * ��ȡ����ֵ
     *
     * @param parameter
     *            �������
     * @return String
     */
    public String getParameter(String parameter) {
        String s = (String) this.parameters.get(parameter);
        return (null == s) ? "" : s;
    }
    /**
     * ���ò���ֵ
     *
     * @param parameter
     *            �������
     * @param parameterValue
     *            ����ֵ
     */
    @SuppressWarnings("unchecked")
    public void setParameter(String parameter, String parameterValue) {
        String v = "";
        if (null != parameterValue) {
            v = parameterValue.trim();
        }
        this.parameters.put(parameter, v);
    }
    /**
     * �������еIJ���
     *
     * @return SortedMap
     */
    @SuppressWarnings("rawtypes")
    public SortedMap getAllParameters() {
        return this.parameters;
    }
    public String getDebugInfo() {
        return debugInfo;
    }
    /**
     * ��ȡ��Կ
     */
    public String getKey() {
        return key;
    }
    /**
     * ������Կ
     */
    public void setKey(String key) {
        this.key = key;
    }
    public String getCharset() {
        return this.charset;
    }
    public void setCharset(String charset) {
        this.charset = charset;
    }
    /**
     * �Ƿ�Ƹ�ͨǩ��,������:���������a-z����,������ֵ�IJ���μ�ǩ��
     *
     * @return boolean
     */
    @SuppressWarnings("rawtypes")
    public boolean isTenpaySign() {
        StringBuffer sb = new StringBuffer();
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + this.getKey());
        System.out.println("返回的参数:" + sb);
        // ���ժҪ
        String sign = MD5Util.MD5Encode(sb.toString(), this.charset)
                .toUpperCase();
        String tenpaySign = this.getParameter("sign").toUpperCase();
        // debug��Ϣ
        this.setDebugInfo(sb.toString() + " => sign:" + sign + " tenpaySign:"
                + tenpaySign);
        Boolean b = tenpaySign.equals(sign);
        System.out.println("验证返回来的数据是否微信返回的:" + b);
        return b;
    }
    /**
     * �Ƿ�Ƹ�ͨǩ��
     *
     * @param signParameterArray
     *            ǩ��IJ�������
     * @return boolean
     */
    protected boolean isTenpaySign(String signParameterArray[]) {
        StringBuffer signPars = new StringBuffer();
        for (int index = 0; index < signParameterArray.length; index++) {
            String k = signParameterArray[index];
            String v = this.getParameter(k);
            if (null != v && !"".equals(v)) {
                signPars.append(k + "=" + v + "&");
            }
        }
        signPars.append("key=" + this.getKey());
        // ���ժҪ
        String sign = MD5Util.MD5Encode(signPars.toString(), this.charset)
                .toLowerCase();
        String tenpaySign = this.getParameter("sign").toLowerCase();
        // debug��Ϣ
        this.setDebugInfo(signPars.toString() + " => sign:" + sign
                + " tenpaySign:" + tenpaySign);
        return tenpaySign.equals(sign);
    }
    protected void setDebugInfo(String debugInfo) {
        this.debugInfo = debugInfo;
    }
    /**
     * ����XML����
     */
    @SuppressWarnings("rawtypes")
    protected void doParse() throws JDOMException, IOException, JDOMException {
        String xmlContent = this.getContent();
        // ����xml,�õ�map
        Map m = XMLUtil.doXMLParse(xmlContent);
        // ���ò���
        Iterator it = m.keySet().iterator();
        while (it.hasNext()) {
            String k = (String) it.next();
            String v = (String) m.get(k);
            this.setParameter(k, v);
        }
    }
}
hx_common/src/main/java/com/hx/mp/util/CorpMpClientUtil.java
New file
@@ -0,0 +1,510 @@
package com.hx.mp.util;
import com.hx.util.StringUtils;
import com.hz.util.http.HttpHzUtil;
import com.hz.util.http.dto.HttpHzResponse;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
/**
 * 企业微信客户工具
 */
public class CorpMpClientUtil {
    /**
     * 生成联系我按钮参数的链接(生成config_id)
     */
    public static final String CREATE_CONTACT_ID_URL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_contact_way?access_token=";
    /**
     * 获取企业客户详情链接
     */
    public static final String GET_CLIENT_DETAIL_URL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get";
    /**
     * 获取获取企业标签库链接
     */
    public static final String GET_CORP_TAG_LIST = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_corp_tag_list?access_token=";
    /**
     * 添加客户联系人标签
     */
    public static final String ADD_TAG = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_corp_tag?access_token=";
    /**
     * 编辑企业客户标签
     */
    public static final String EDIT_TAG = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/edit_corp_tag?access_token=";
    /**
     * 删除客户联系人标签
     */
    public static final String DEL_TAG = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/del_corp_tag?access_token=";
    /**
     * 客户关联企业微信的标签url
     */
    public static final String RELATION_TAG = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/mark_tag?access_token=";
    /**
     * 获取员工客户列表url
     */
    public static final String EXTERNAL_CONTACT_LIST = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list";
    /**
     * 创建获客链接url
     */
    public static final String CUSTOMER_ACQUISITION_CREATE_LINK = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/create_link?access_token=";
    /**
     * 获取获客客户列表
     */
    public static final String CUSTOMER_ACQUISITION_CUSTOMER_LIST = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/customer?access_token=";
    /**
     * 获取配置过客户群管理的客户群列表
     */
    public static final String GROUP_CHAT_LIST = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/list?access_token=";
    /**
     * 通过客户群ID,获取详情。包括群名、群成员列表、群成员入群时间、入群方式。(客户群是由具有客户群使用权限的成员创建的外部群)
     */
    public static final String GROUP_CHAT_DETAIL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/get?access_token=";
    /**
     * 企业微信发送普通邮件
     */
    public static final String GROUP_SENT_EMAIL = "https://qyapi.weixin.qq.com/cgi-bin/exmail/app/compose_send?access_token=";
    /**
     * 客户群「加入群聊」查看
     */
    public static final String GROUP_JOIN_WAY_SEE = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/get_join_way?access_token=";
    /**
     * 客户群「加入群聊」新增
     * 企业可调用此接口来生成并配置「加入群聊」的二维码或者小程序按钮
     * 客户通过扫描二维码或点击小程序上的按钮,即可加入特定的客户群
     */
    public static final String GROUP_JOIN_WAY_ADD = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/add_join_way?access_token=";
    /**
     * 客户群「加入群聊」修改
     */
    public static final String GROUP_JOIN_WAY_EDIT = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/update_join_way?access_token=";
    /**
     * 客户群「加入群聊」删除
     */
    public static final String GROUP_JOIN_WAY_EDL= "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/del_join_way?access_token=";
    /**
     * 生成企业成员联系我的id-单人
     *
     * @param accessToken 企业的accessToken
     * @param userId      企业成员的userId
     * @param state       企业自定义的state参数,用于区分不同的添加渠道,在调用“获取外部联系人详情”时会返回该参数值,不超过30个字符
     * @param remark      联系方式的备注信息,用于助记,不超过30个字符
     * @return 返回
     */
    public static JSONObject createContactId(String accessToken, String userId, String state, String remark) {
        String configId = null;
        JSONObject data = new JSONObject();
        data.put("type", 1);
        data.put("scene", 1);
        data.put("state", state);
        data.put("remark", remark);
        JSONArray userIds = new JSONArray();
        userIds.add(userId);
        data.put("user", userIds);
        //请求,返回格式
       /*{
           "errcode": 0,
               "errmsg": "ok",
               "config_id":"42b34949e138eb6e027c123cba77fAAA"  
       }*/
        return HttpURLUtil(CREATE_CONTACT_ID_URL + accessToken, data.toString());
    }
    /**
     * 获取客户列表
     * @param accessToken 企业的accessToken
     * @param userId 企业成员的userId
     * @return 返回
     */
    public static JSONObject getExternalContactList(String accessToken, String userId) {
        return HttpURLUtil(EXTERNAL_CONTACT_LIST + "?access_token=" + accessToken + "&userid=" + userId, null);
    }
    /**
     * 获取企业客户详情信息
     *
     * @param accessToken    企业的accessToken
     * @param externalUserId 外部人员的userId
     * @return 返回
     */
    public static JSONObject getClientData(String accessToken, String externalUserId) {
        return HttpURLUtil(GET_CLIENT_DETAIL_URL + "?access_token=" + accessToken + "&external_userid=" + externalUserId, null);
    }
    /**
     * 企业可通过此接口获取企业客户标签详情
     *
     * @param accessToken 企业的accessToken
     * @param tagId  标签id
     * @param groupId 标签组id
     * @return 返回
     */
    public static JSONObject getCorpTagList(String accessToken, JSONArray tagId, JSONArray groupId) {
        JSONObject data = new JSONObject();
        data.put("tag_id", tagId);
        data.put("group_id", groupId);
        return HttpURLUtil(GET_CORP_TAG_LIST + accessToken, data.toString());
    }
    /**
     * 添加客户联系人标签,
     * 如果要向指定的标签组下添加标签,需要填写group_id参数;如果要创建一个全新的标签组以及标签,
     * 则需要通过group_name参数指定新标签组名称,如果填写的groupname已经存在,则会在此标签组下新建标签
     *
     * @param accessToken 企业的accessToken
     * @param groupId     组id(组名称和组id必填一个)
     * @param groupName   组名称 组名称和组id必填一个)
     * @param groupOrder  组排序,不填默认企业微信生成规则
     * @param tagArray    数组,格式:[{ "name": "TAG_NAME_1", "order": 1 }]
     * @return 返回
     */
    public static JSONObject addTable(String accessToken, String groupId, String groupName, String groupOrder, JSONArray tagArray) {
        JSONObject data = new JSONObject();
        data.put("group_id", groupId);
        data.put("group_name", groupName);
        data.put("order", groupOrder);
        data.put("tag", tagArray);
        return HttpURLUtil(ADD_TAG + accessToken, data.toString());
    }
    /**
     * 编辑企业客户标签,
     * 注意:修改后的标签组不能和已有的标签组重名,标签也不能和同一标签组下的其他标签重名。
     *
     * @param accessToken 企业的accessToken
     * @param id     标签或标签组的id
     * @param name   新的标签或标签组名称,最长为30个字符
     * @param order  标签/标签组的次序值。order值大的排序靠前。有效的值范围是[0, 2^32)
     * @return 返回
     */
    public static JSONObject editTable(String accessToken, String id, String name, String order) {
        JSONObject data = new JSONObject();
        data.put("id", id);
        data.put("name", name);
        data.put("order", order);
        return HttpURLUtil(EDIT_TAG + accessToken, data.toString());
    }
    /**
     * 删除客户联系人标签
     * groupArr和tagArr不可同时为空。
     * 如果一个标签组下所有的标签均被删除,则标签组会被自动删除。
     *
     * @param accessToken 企业的accessToken
     * @param groupArr    组id数组
     * @param tagArr      标签id数组
     * @return 返回
     */
    public static JSONObject delTable(String accessToken, JSONArray groupArr, JSONArray tagArr) {
        JSONObject data = new JSONObject();
        data.put("tag_id", tagArr);
        data.put("group_id", groupArr);
        return HttpURLUtil(DEL_TAG + accessToken, data.toString());
    }
    /**
     * 客户关联企业微信的标签
     * 注意:请确保external_userid是userid的外部联系人。
     * add_tag和remove_tag不可同时为空。
     *
     * @param accessToken    企业的accessToken
     * @param userId         企业成员的userid
     * @param externalUserId 外部联系人的id
     * @param addTag         新增的标签id(企业标签的id)数组
     * @param removeTag      删除的标签id(企业标签的id)数组
     * @return 返回
     */
    public static JSONObject relationTag(String accessToken, String userId, String externalUserId, JSONArray addTag, JSONArray removeTag) {
        JSONObject data = new JSONObject();
        data.put("userid", userId);
        data.put("external_userid", externalUserId);
        data.put("add_tag", addTag);
        data.put("remove_tag", removeTag);
        return HttpURLUtil(RELATION_TAG + accessToken, data.toString());
    }
    /**
     * 请求http协议 获取信息工具
     **/
    public static JSONObject HttpURLUtil(String url, String data) {
        HttpURLConnection con = null;
        URL u = null;
        String wxMsgXml = null;
        JSONObject obj = null;
        try {
            u = new URL(url);
            con = (HttpURLConnection) u.openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setReadTimeout(5000);
            con.setRequestProperty("Charset", "UTF-8");
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            if (data != null) {
                OutputStream os = con.getOutputStream();
                os.write(data.getBytes("utf-8"));
            }
            if (con.getResponseCode() != 200)
                throw new RuntimeException("请求url失败");
            // 读取返回内容
            wxMsgXml = IOUtils.toString(con.getInputStream(), "utf-8");
            obj = JSONObject.fromObject(wxMsgXml);
            // //System.out.println("HttpURLUtil:"+wxMsgXml);
        } catch (Exception e) {
            e.printStackTrace();
            obj = new JSONObject();
            try {
                obj.put("status", 1);
                obj.put("errMsg", e.getMessage());
            } catch (JSONException e1) {
                e1.printStackTrace();
            }
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        return obj;
    }
    /**生成企业成员联系我的id-单人
     * @param accessToken 企业的accessToken
     * @param userId 企业成员的userId
     * @param scene 场景,1-在小程序中联系,2-通过二维码联系
     * @param state 企业自定义的state参数,用于区分不同的添加渠道,在调用“获取外部联系人详情”时会返回该参数值,不超过30个字符
     * @param remark 联系方式的备注信息,用于助记,不超过30个字符
     * @return 返回
     */
    public static JSONObject createContactId(String accessToken,String userId,int scene,String state,String remark){
        String configId = null;
        JSONObject data = new JSONObject();
        data.put("type",1);
        data.put("scene",scene);
        data.put("state",state);
        data.put("remark",remark);
        JSONArray userIds = new JSONArray();
        userIds.add(userId);
        data.put("user",userIds);
        //请求,返回格式
       /*{
           "errcode": 0,
               "errmsg": "ok",
               "config_id":"42b34949e138eb6e027c123cba77fAAA"  
       }*/
        return HttpURLUtil(CREATE_CONTACT_ID_URL+accessToken,data.toString());
    }
    /**
     * 创建获客链接
     *
     * @param accessToken 企业的accessToken
     * @param linkName  链接名称
     * @param userList 员工用户userId
     * @return 返回
     */
    public static JSONObject createCustomerAcquisitionLink(String accessToken, String linkName, JSONArray userList) {
        JSONObject data = new JSONObject();
        data.put("link_name", linkName);
        JSONObject subData = new JSONObject();
        subData.accumulate("user_list", userList);
        data.put("range", subData);
        /** 返回数据
         * {
         *    "link_id":"LINK_ID",
         *    "link_name":"获客链接1号",
         *    "range":
         *    {
         *            "user_list":["zhangsan","lisi"],
         *         "department_list":[2,3]
         *    },
         *    "skip_verify":true
         * }
         */
        return HttpURLUtil(CUSTOMER_ACQUISITION_CREATE_LINK + accessToken, data.toString());
    }
    /**
     * 获取获客客户列表
     *
     * @param accessToken 企业的accessToken
     * @param linkId  链接id
     * @param cursor  分页游标
     * @return 返回
     */
    public static JSONObject getCustomerAcquisitionCustomerList(String accessToken, String linkId, String cursor) {
        JSONObject data = new JSONObject();
        data.put("link_id", linkId);
        data.put("limit", 1000);
        // 分页游标
        if (!StringUtils.isEmpty(cursor)) {
            data.put("cursor", cursor);
        }
        /** 返回数据
         * {
         *     "errcode": 0,
         *     "errmsg": "ok",
         *     "customer_list":
         *     [
         *                {
         *             "external_userid":"woAJ2GCAAAXtWyujaWJHDDGi0mACAAA",
         *             "userid":"zhangsan",
         *             "chat_status":0,
         *             "state":"CHANNEL_A"
         *        }
         *     ],
         *     "next_cursor":"CURSOR"
         * }
         */
        return HttpURLUtil(CUSTOMER_ACQUISITION_CUSTOMER_LIST + accessToken, data.toString());
    }
    /**
     * 该接口用于获取配置过客户群管理的客户群列表。
     *
     * @param accessToken  企业的accessToken
     * @param statusFilter 客户群跟进状态过滤。0 - 所有列表(即不过滤) 1 - 离职待继承 2 - 离职继承中 3 - 离职继承完成
     * @param userIdList   群主过滤 如果不填,表示获取应用可见范围内全部群主的数据可见范围人数超过1000人,为了防止数据包过大,会报错 81017 用户ID列表。最多100个
     * @param cursor       分页下标
     * @param limit        列表
     * @return 返回
     */
    public static HttpHzResponse getGroupChatList(String accessToken, Integer statusFilter, List<String> userIdList, String cursor, Integer limit) {
        JSONObject bodyData = new JSONObject();
        bodyData.put("status_filter", statusFilter);
        //分页下标
        if (StringUtils.noNull(cursor)) {
            bodyData.put("cursor", cursor);
        }
        //默认100条
        if (limit == null) {
            limit = 100;
        }
        bodyData.put("limit", limit);
        //过滤
        if (userIdList != null && userIdList.size() > 0) {
            JSONObject filter = new JSONObject();
            filter.put("userid_list", userIdList);
            bodyData.put("owner_filter", filter);
        }
        return HttpHzUtil.HttpURLUtilJson(GROUP_CHAT_LIST + accessToken, bodyData.toString(), null, null, "GET", null);
    }
    /**
     * 通过客户群ID,获取详情。包括群名、群成员列表、群成员入群时间、入群方式。(客户群是由具有客户群使用权限的成员创建的外部群)
     *
     * @param chatId   客户群ID
     * @param needName 是否需要返回群成员的名字0-不返回;1-返回
     */
    public static HttpHzResponse getGroupChatDetail(String accessToken, String chatId, Integer needName) {
        JSONObject bodyData = new JSONObject();
        bodyData.put("chat_id", chatId);
        if (needName == null) {
            needName = 0;
        }
        bodyData.put("need_name", needName);
        return HttpHzUtil.HttpURLUtilJson(GROUP_CHAT_DETAIL + accessToken, bodyData.toString(), null, null, "GET", null);
    }
    /**
     * 企业微信发送普通邮件
     * 接口地址: https://developer.work.weixin.qq.com/document/path/97445
     * @param bodyData  参数
     */
    public static JSONObject sentEmail(String accessToken, JSONObject bodyData) {
        return HttpURLUtil(GROUP_SENT_EMAIL + accessToken, bodyData.toString());
    }
    /**
     * 客户群「加入群聊」查看详情
     * @param config_id 联系方式配置ID
     * */
    public static HttpHzResponse groupJoinSee(String accessToken, String config_id) {
        JSONObject bodyData = new JSONObject();
        bodyData.put("config_id", config_id);
        return HttpHzUtil.HttpURLUtilJson(GROUP_JOIN_WAY_SEE + accessToken, bodyData.toString(), null, null, "POST", null);
    }
    /**
     * 客户群「加入群聊」新增
     * @param scene 场景。1 - 群的小程序插件, 2 - 群的二维码插件
     * @param remark 联系方式的备注信息,用于助记,超过30个字符将被截断
     * @param auto_create_room 当群满了后,是否自动新建群。0-否;1-是。 默认为1
     * @param room_base_name 自动建群的群名前缀,当auto_create_room为1时有效。最长40个utf8字符
     * @param room_base_id 自动建群的群起始序号,当auto_create_room为1时有效
     * @param chat_id_list 使用该配置的客户群ID列表,最多支持5个
     * */
    public static HttpHzResponse groupJoinAdd(String accessToken, Integer scene, String remark
            ,Integer auto_create_room,String room_base_name,Integer room_base_id,List<String> chat_id_list,String state) {
        JSONObject bodyData = new JSONObject();
        bodyData.put("scene", scene);
        bodyData.put("remark", remark);
        bodyData.put("auto_create_room", auto_create_room);
        bodyData.put("room_base_name", room_base_name);
        bodyData.put("room_base_id", room_base_id);
        bodyData.put("chat_id_list", chat_id_list);
        bodyData.put("state", state);
        return HttpHzUtil.HttpURLUtilJson(GROUP_JOIN_WAY_ADD + accessToken, bodyData.toString(), null, null, "POST", null);
    }
    /**
     * 客户群「加入群聊」修改
     * @param config_id 联系方式配置ID
     * @param scene 场景。1 - 群的小程序插件, 2 - 群的二维码插件
     * @param remark 联系方式的备注信息,用于助记,超过30个字符将被截断
     * @param auto_create_room 当群满了后,是否自动新建群。0-否;1-是。 默认为1
     * @param room_base_name 自动建群的群名前缀,当auto_create_room为1时有效。最长40个utf8字符
     * @param room_base_id 自动建群的群起始序号,当auto_create_room为1时有效
     * @param chat_id_list 使用该配置的客户群ID列表,最多支持5个
     * */
    public static HttpHzResponse groupJoinEdit(String accessToken,String config_id, Integer scene, String remark
            ,Integer auto_create_room,String room_base_name,Integer room_base_id,List<String> chat_id_list,String state) {
        JSONObject bodyData = new JSONObject();
        bodyData.put("config_id", config_id);
        bodyData.put("scene", scene);
        bodyData.put("remark", remark);
        bodyData.put("auto_create_room", auto_create_room);
        bodyData.put("room_base_name", room_base_name);
        bodyData.put("room_base_id", room_base_id);
        bodyData.put("chat_id_list", chat_id_list);
        bodyData.put("state", state);
        return HttpHzUtil.HttpURLUtilJson(GROUP_JOIN_WAY_EDIT + accessToken, bodyData.toString(), null, null, "POST", null);
    }
    /**
     * 客户群「加入群聊」删除
     * @param config_id 联系方式配置ID
     * */
    public static HttpHzResponse groupJoinDel(String accessToken, String config_id) {
        JSONObject bodyData = new JSONObject();
        bodyData.put("config_id", config_id);
        return HttpHzUtil.HttpURLUtilJson(GROUP_JOIN_WAY_EDL + accessToken, bodyData.toString(), null, null, "POST", null);
    }
}
hx_common/src/main/java/com/hx/mp/util/CorpMpSpaceUtil.java
New file
@@ -0,0 +1,238 @@
package com.hx.mp.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hx.api.CorpMpSpaceApi;
import java.util.List;
/**
 * 企业微信微盘接口API
 * @Author: cmg
 * @Date: 2023-7-13 11:08
 */
public class CorpMpSpaceUtil {
    /**
     * 增加空间
     * @param corpMpSpaceApi
     * @param accessToken
     * @param name 空间名称
     * @param depId 部门id
     * @param adminId 管理员的企业微信id
     * @return
     */
    public static JSONObject addSpace(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String name, Integer depId, String adminId)
    {
        JSONObject obj = new JSONObject();
        obj.put("space_name", name);
        JSONArray arr = new JSONArray();
        //设置部门的可下载权限
        JSONObject temp = new JSONObject();
        temp.put("type", 2);
        temp.put("departmentid", depId);
        temp.put("auth", 1);
        arr.add(temp);
        //设置管理员
        temp = new JSONObject();
        temp.put("type", 1);
        temp.put("userid", adminId);
        temp.put("auth", 7);
        arr.add(temp);
        obj.put("auth_info", arr);
        return corpMpSpaceApi.addSpace(accessToken, obj.toJSONString());
    }
    /**
     * 空间重命名
     * @param corpMpSpaceApi
     * @param accessToken
     * @param spaceId
     * @param name
     * @return
     */
    public static JSONObject editSpaceName(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String spaceId, String name)
    {
        JSONObject obj = new JSONObject();
        obj.put("space_name", name);
        obj.put("spaceid", spaceId);
        return corpMpSpaceApi.renameSpace(accessToken, obj.toJSONString());
    }
    /**
     * 空间设置
     * @param corpMpSpaceApi
     * @param accessToken
     * @param spaceId
     * @param enableConfidentialMode
     * @return
     */
    public static JSONObject spaceSetting(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String spaceId, boolean enableConfidentialMode)
    {
        JSONObject obj = new JSONObject();
        obj.put("spaceid", spaceId);
        obj.put("enable_confidential_mode", enableConfidentialMode);
        return corpMpSpaceApi.spaceSetting(accessToken, obj.toJSONString());
    }
    /**
     * 创建文件夹
     * @param corpMpSpaceApi
     * @param accessToken
     * @param spaceId 空间id
     * @param fatherId 上级目录id,如果是空间下第一级,则是空间id
     * @param fileName 文件夹名称
     * @return
     */
    public static JSONObject createDir(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String spaceId, String fatherId, String fileName)
    {
        JSONObject param = new JSONObject();
        param.put("spaceid", spaceId);
        param.put("fatherid", fatherId);
        param.put("file_type", 1);
        param.put("file_name", fileName);
        return corpMpSpaceApi.createFile(accessToken, param.toJSONString());
    }
    /**
     * 文件/文件夹重命名
     * @param corpMpSpaceApi
     * @param accessToken
     * @param fileId
     * @param fileName
     * @return
     */
    public static JSONObject editDirName(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String fileId, String fileName)
    {
        JSONObject param = new JSONObject();
        param.put("fileid", fileId);
        param.put("new_name", fileName);
        return corpMpSpaceApi.renameFile(accessToken, param.toJSONString());
    }
    /**
     * 移除文件夹
     * @param corpMpSpaceApi
     * @param accessToken
     * @param fileId
     * @return
     */
    public static JSONObject deleteDir(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String fileId)
    {
        JSONObject param = new JSONObject();
        JSONArray arr = new JSONArray();
        arr.add(fileId);
        param.put("fileid", arr);
        return corpMpSpaceApi.deleteFile(accessToken, param.toJSONString());
    }
    /**
     * 传10M以内文件
     * @param corpMpSpaceApi
     * @param accessToken
     * @param name
     * @param fileBase64Content
     * @param spaceId
     * @param fatherId
     * @return
     */
    public static JSONObject uploadFile(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String name, String fileBase64Content, String spaceId, String fatherId) {
        JSONObject param = new JSONObject();
        param.put("spaceid", spaceId);
        param.put("fatherid", fatherId);
        param.put("file_name", name);
        param.put("file_base64_content", fileBase64Content);
        return corpMpSpaceApi.fileUpload(accessToken, param.toJSONString());
    }
    /**
     * 分块上传文件-初始化
     * @param corpMpSpaceApi
     * @param accessToken
     * @param spaceId
     * @param fatherId
     * @param selectTicket
     * @param fileName
     * @param size
     * @param skipPushCard
     * @param blockSha
     * @return
     */
    public static JSONObject uploadBigFileInit(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String spaceId, String fatherId,
                                               String selectTicket, String fileName, Long size, boolean skipPushCard, List<String> blockSha) {
        JSONObject param = new JSONObject();
        param.put("spaceid", spaceId);
        param.put("fatherid", fatherId);
        param.put("selected_ticket", selectTicket);
        param.put("file_name", fileName);
        param.put("size", size);
        param.put("skip_push_card", skipPushCard);
        JSONArray arr = new JSONArray();
        for(String sha : blockSha)
        {
            arr.add(sha);
        }
        param.put("block_sha", arr);
        return corpMpSpaceApi.fileUploadInit(accessToken, param.toJSONString());
    }
    /**
     * 分块上传文件-部分上传
     * @param corpMpSpaceApi
     * @param accessToken
     * @param uploadKey
     * @param index
     * @param fileBase64Content
     * @return
     */
    public static JSONObject uploadBigFilePart(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String uploadKey, int index, String fileBase64Content) {
        JSONObject param = new JSONObject();
        param.put("upload_key", uploadKey);
        param.put("index", index);
        param.put("file_base64_content", fileBase64Content);
        return corpMpSpaceApi.fileUploadPart(accessToken, param.toJSONString());
    }
    /**
     * 分块上传文件-上传完成
     * @param corpMpSpaceApi
     * @param accessToken
     * @param uploadKey
     * @return
     */
    public static JSONObject uploadBigFileFin(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String uploadKey) {
        JSONObject param = new JSONObject();
        param.put("upload_key", uploadKey);
        return corpMpSpaceApi.fileUploadFinish(accessToken, param.toJSONString());
    }
    /**
     * 获取下载路径
     * @param corpMpSpaceApi
     * @param accessToken
     * @param fileId
     * @return
     */
    public static JSONObject getDownloadUrl(CorpMpSpaceApi corpMpSpaceApi, String accessToken, String fileId){
        JSONObject param = new JSONObject();
        param.put("fileid", fileId);
        return corpMpSpaceApi.getDownloadUrl(accessToken, param.toJSONString());
    }
}
hx_common/src/main/java/com/hx/mp/util/CorpMpUtil.java
New file
@@ -0,0 +1,347 @@
package com.hx.mp.util;
import com.hx.util.corp.entity.AppLetInfo;
import com.hx.exception.TipsException;
import com.hx.util.HttpMethodUtil;
import com.hx.util.StringUtils;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
/**
 * 企业微信工具类
 */
public class CorpMpUtil {
    /**链接-获取应用accessToken*/
    public static final String URL_GET_ACCESS_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={0}&corpsecret={1}";
    /**链接-获取session信息*/
    public static final String URL_CODE_2_SESSION = "https://qyapi.weixin.qq.com/cgi-bin/miniprogram/jscode2session?access_token={0}&js_code={1}&grant_type=authorization_code";
    /**链接-添加标签*/
    public static final String URL_ADD_LABEL = "https://qyapi.weixin.qq.com/cgi-bin/tag/create?access_token={0}";
    /**链接-添加部门*/
    public static final String URL_ADD_DEPARTMENT = "https://qyapi.weixin.qq.com/cgi-bin/department/create?access_token={0}";
    /**链接-修改部门*/
    public static final String URL_UPDATE_DEPARTMENT = "https://qyapi.weixin.qq.com/cgi-bin/department/update?access_token={0}";
    /**链接-删除部门*/
    public static final String URL_DELETE_DEPARTMENT = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?access_token={0}&id={1}";
    /**链接-添加成员*/
    public static final String URL_ADD_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token={0}";
    /**链接-更新成员*/
    public static final String URL_UPDATE_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/update?access_token={0}";
    /**链接-删除成员*/
    public static final String URL_DELETE_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?access_token={0}&userid={1}";
    /**链接-成员详情*/
    public static final String URL_INFO_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token={0}&userid={1}";
    /**发送消息*/
    public static final String URL_MESSAGE_SEND = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";
    /**
     * 添加工作人员
     * @param at 访问at
     * @param userId 用户id
     * @param name 名称
     * @param depId 部门id
     * @param position 职位
     * @param tel 电话
     * @param email 邮箱
     * @return 返回
     */
    public static int addUser(String at, String userId, String name, int depId
            , String position,String tel,String email) {
        if(StringUtils.isEmpty(tel)&&StringUtils.isEmpty(email)){
            throw new TipsException("添加企业微信手机号和邮箱不能都为空!");
        }
        JSONObject obj = new JSONObject();
        obj.put("userid", userId);
        obj.put("name", name);
        obj.put("department", depId);
        obj.put("position", position);
        obj.put("mobile", tel);
        obj.put("email", email);
        obj = HttpURLUtil(MessageFormat.format(URL_ADD_USER, at), obj.toString());
        if(obj != null) {
            return obj.optInt("errcode", -1);
        }
        return -1;
    }
    /**
     * 添加工作人员
     * @param at 访问at
     * @param userId 用户id
     * @param name 名称
     * @param depId 部门id
     * @param position 职位
     * @param tel 电话
     * @param email 邮箱
     * @return 返回
     */
    public static JSONObject addUserObj(String at, String userId, String name, int depId
            , String position,String tel,String email) {
        if(StringUtils.isEmpty(tel)&&StringUtils.isEmpty(email)){
            throw new TipsException("添加企业微信手机号和邮箱不能都为空!");
        }
        JSONObject obj = new JSONObject();
        obj.put("userid", userId);
        obj.put("name", name);
        obj.put("department", depId);
        obj.put("position", position);
        obj.put("mobile", tel);
        obj.put("email", email);
        obj = HttpURLUtil(MessageFormat.format(URL_ADD_USER, at), obj.toString());
        if(obj == null){
            obj = new JSONObject();
        }
        return obj;
    }
    /**
     * 更新工作人员
     * @param at 访问at
     * @param userId 用户id
     * @param name 名称
     * @param depId 部门id
     * @param position 职位
     * @param tel 电话
     * @param email 邮箱
     * @return 返回
     */
    public static int updateUser(String at, String userId, String name, int depId
            , String position,String tel,String email) {
        JSONObject obj = new JSONObject();
        obj.put("userid", userId);
        obj.put("name", name);
        obj.put("department", depId);
        obj.put("position", position);
        obj.put("mobile", tel);
        obj.put("email", email);
        obj = HttpURLUtil(MessageFormat.format(URL_UPDATE_USER, at), obj.toString());
        if(obj != null && obj.optInt("errcode", -1) == 0) {
            return obj.optInt("errcode", -1);
        }
        return -1;
    }
    /**
     * 删除工作人员
     * @param at 访问at
     * @param userId 企业用户id
     * @return 返回
     */
    public static int deleteUser(String at, String userId) {
        JSONObject obj = new JSONObject();
        obj.put("userid", userId);
        obj = HttpURLUtil(MessageFormat.format(URL_DELETE_USER, at,userId), obj.toString());
        if(obj != null) {
            return obj.optInt("errcode", -1);
        }
        return -1;
    }
    /**
     * 工作人员判断是否存在企业微信
     * @param at 访问at
     * @param userId 用户id
     * @return 返回
     */
    public static int infoUser(String at, String userId) {
        JSONObject obj = new JSONObject();
        obj.put("userid", userId);
        obj = HttpURLUtil(MessageFormat.format(URL_INFO_USER, at,userId), obj.toString());
        if(obj != null) {
            return obj.optInt("errcode", -1);
        }
        return -1;
    }
    /**
     * 获取企业用户信息
     * @param at 访问at
     * @param userId 用户id
     * @return 返回
     */
    public static JSONObject userData(String at, String userId) {
        JSONObject obj = new JSONObject();
        obj.put("userid", userId);
        return obj = HttpURLUtil(MessageFormat.format(URL_INFO_USER, at,userId), obj.toString());
    }
    /**
     * 添加部门
     * @param name 部门名称
     * @return id
     */
    public static int addDepartment(String at, String name, int parentId) {
        JSONObject obj = new JSONObject();
        obj.put("name", name);
        obj.put("parentid", parentId);
        obj = HttpURLUtil(MessageFormat.format(URL_ADD_DEPARTMENT, at), obj.toString());
        if(obj != null && obj.optInt("errcode", -1) == 0) {
            return obj.optInt("id", -1);
        }
        return -1;
    }
    /**
     * 更新部门
     * @param name 部门名称
     * @param deaprtId 部门id
     * @param parentid 父类部门id,可以为空
     * @return  状态,0成功
     */
    public static int updateDepartment(String at, String name, int deaprtId,int parentid) {
        JSONObject obj = new JSONObject();
        obj.put("name", name);
        obj.put("id", deaprtId);
        obj.put("parentid", parentid);
        obj = HttpURLUtil(MessageFormat.format(URL_UPDATE_DEPARTMENT, at), obj.toString());
        return obj.optInt("errcode", -1);
    }
    /**删除部门
     * 删除的部门不能是根部门且没有成员
     * @param deaprtId 部门id
     * @return 状态,0成功
     */
    public static int deleteDepartment(String at,int deaprtId) {
        JSONObject obj = new JSONObject();
        obj.put("id", deaprtId);
        obj = HttpURLUtil(MessageFormat.format(URL_DELETE_DEPARTMENT,at,deaprtId), obj.toString());
        System.out.println("删除部门:"+obj.toString());
        return obj.optInt("errcode", -1);
    }
    /**发送企业应用消息
     * @param accessToken 企业accessToken
     * @param data 发送数据结构
     * @return
     */
    public static JSONObject messageSend(String accessToken,String data){
        return HttpURLUtil(URL_MESSAGE_SEND+accessToken,data);
    }
    /**添加用户标签,标签名称不能重复
     * @param at 访问at
     * @param label 标签名称
     * @return 返回 -1失败,0成功,1已存在
     */
    public static int addLabel(String at, String label) {
        String url = MessageFormat.format(URL_ADD_LABEL, at);
        JSONObject obj = new JSONObject();
        obj.put("tagname", label);
        obj = HttpURLUtil(url, obj.toString());
        System.out.println("obj....:"+obj.toString());
        if(obj != null ) {
            int errcode = obj.optInt("errcode", -1);
            if( errcode== 0){
                //上传成功
                return obj.optInt("tagid", -1);
            }if(errcode == 40071){
                //标签已经存在
                return 1;
            }
        }
        return -1;
    }
    /**
     * 获取应用accessToken
     * @param corpId 企业id
     * @param appSecret 应用密钥
     * @return
     * @throws Exception
     */
    public static JSONObject getApplicationAccessToken(String corpId, String appSecret) {
        String url = MessageFormat.format(URL_GET_ACCESS_TOKEN, corpId, appSecret);
        JSONObject obj = HttpURLUtil(url, null);
        return obj;
    }
    /**
     * 使用临时登录凭证code获取 session_key、用户userId以及用户所在企业的corpId等信息
     * @param accessToken 访问token
     * @param code 临时code
     * @return
     */
    public static JSONObject code2Session(String accessToken, String code) {
        String url = MessageFormat.format(URL_CODE_2_SESSION, accessToken, code);
        JSONObject obj = HttpURLUtil(url, null);
        return obj;
    }
    /** 请求http协议 获取信息工具 **/
    public static JSONObject HttpURLUtil(String url, String data) {
        HttpURLConnection con = null;
        URL u = null;
        String wxMsgXml = null;
        JSONObject obj = null;
        try {
            u = new URL(url);
            con = (HttpURLConnection) u.openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setReadTimeout(5000);
            con.setRequestProperty("Charset", "UTF-8");
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            if (data != null) {
                OutputStream os = con.getOutputStream();
                os.write(data.getBytes("utf-8"));
            }
            if (con.getResponseCode() != 200)
                throw new RuntimeException("请求url失败");
            // 读取返回内容
            wxMsgXml = IOUtils.toString(con.getInputStream(), "utf-8");
            obj = JSONObject.fromObject(wxMsgXml);
            // //System.out.println("HttpURLUtil:"+wxMsgXml);
        } catch (Exception e) {
            e.printStackTrace();
            obj = new JSONObject();
            try {
                obj.put("status", 1);
                obj.put("errMsg", e.getMessage());
            } catch (JSONException e1) {
                e1.printStackTrace();
            }
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        return obj;
    }
}
hx_common/src/main/java/com/hx/mp/util/CorpWXPayQrUtil.java
New file
@@ -0,0 +1,73 @@
package com.hx.mp.util;
import com.hx.exception.ServiceException;
import com.hx.util.HttpUtil;
import com.hx.util.SimpleTool;
import com.hx.util.StringUtils;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.*;
/** 服务商商户Native(二维码扫码支付)
 * @author ChenJiaHe
 */
public class CorpWXPayQrUtil {
    /**服务商-获取二维码支付数据*/
    private static final String PAY_NATIVE_URL = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/native";
    /**获取支付二维码数据
     * @param sp_appid 服务商申请的公众号appid
     * @param sp_mchid 服务商户号
     * @param sub_appid 子商户申请的公众号appid 不必填
     * @param sub_mchid 子商户的商户号
     * @param description 商品描述
     * @param out_trade_no 商户系统内部订单号
     * @param amount 金额(分)
     * @param notify_url 回调地址
     * @return
     * @throws Exception
     */
    public static JSONObject nativeQr(String sp_appid , String sp_mchid , String sub_appid
            , String sub_mchid , String description , String out_trade_no , Integer amount
            ,String notify_url  )
            throws Exception {
        JSONObject parameters = new JSONObject();
        parameters.put("sp_appid", sp_appid);
        parameters.put("sp_mchid", sp_mchid);
        parameters.put("sub_appid", sub_appid);
        parameters.put("sub_mchid", sub_mchid);
        parameters.put("description", description);
        parameters.put("out_trade_no", out_trade_no);
        parameters.put("notify_url", notify_url);
        JSONObject amountObj = new  JSONObject();
        amountObj.put("total",amount);
        amountObj.put("currency","CNY");
        parameters.put("amount", amountObj);
        JSONObject returnObj = HttpUtil.HttpURLUtilJson(PAY_NATIVE_URL,parameters.toString());
        return returnObj;
    }
}
hx_common/src/main/java/com/hx/mp/util/HttpClientUtil.java
New file
@@ -0,0 +1,340 @@
package com.hx.mp.util;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
/**
 * Http�ͻ��˹�����<br/>
 * �����ڲ������࣬�벻Ҫ���ⲿ���á�
 * @author miklchen
 *
 */
public class HttpClientUtil {
    public static final String SunX509 = "SunX509";
    public static final String JKS = "JKS";
    public static final String PKCS12 = "PKCS12";
    public static final String TLS = "TLS";
    /**
     * get HttpURLConnection
     * @param strUrl url��ַ
     * @return HttpURLConnection
     * @throws IOException
     */
    public static HttpURLConnection getHttpURLConnection(String strUrl)
            throws IOException {
        URL url = new URL(strUrl);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url
                .openConnection();
        return httpURLConnection;
    }
    /**
     * get HttpsURLConnection
     * @param strUrl url��ַ
     * @return HttpsURLConnection
     * @throws IOException
     */
    public static HttpsURLConnection getHttpsURLConnection(String strUrl)
            throws IOException {
        URL url = new URL(strUrl);
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url
                .openConnection();
        return httpsURLConnection;
    }
    /**
     * ��ȡ�����ѯ����url
     * @param strUrl
     * @return String
     */
    public static String getURL(String strUrl) {
        if(null != strUrl) {
            int indexOf = strUrl.indexOf("?");
            if(-1 != indexOf) {
                return strUrl.substring(0, indexOf);
            }
            return strUrl;
        }
        return strUrl;
    }
    /**
     * ��ȡ��ѯ��
     * @param strUrl
     * @return String
     */
    public static String getQueryString(String strUrl) {
        if(null != strUrl) {
            int indexOf = strUrl.indexOf("?");
            if(-1 != indexOf) {
                return strUrl.substring(indexOf+1, strUrl.length());
            }
            return "";
        }
        return strUrl;
    }
    /**
     * ��ѯ�ַ�ת����Map<br/>
     * name1=key1&name2=key2&...
     * @param queryString
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Map queryString2Map(String queryString) {
        if(null == queryString || "".equals(queryString)) {
            return null;
        }
        Map m = new HashMap();
        String[] strArray = queryString.split("&");
        for(int index = 0; index < strArray.length; index++) {
            String pair = strArray[index];
            HttpClientUtil.putMapByPair(pair, m);
        }
        return m;
    }
    /**
     * �Ѽ�ֵ�����Map<br/>
     * pair:name=value
     * @param pair name=value
     * @param m
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void putMapByPair(String pair, Map m) {
        if(null == pair || "".equals(pair)) {
            return;
        }
        int indexOf = pair.indexOf("=");
        if(-1 != indexOf) {
            String k = pair.substring(0, indexOf);
            String v = pair.substring(indexOf+1, pair.length());
            if(null != k && !"".equals(k)) {
                m.put(k, v);
            }
        } else {
            m.put(pair, "");
        }
    }
    /**
     * BufferedReaderת����String<br/>
     * ע��:���ر���Ҫ���д���
     * @param reader
     * @return String
     * @throws IOException
     */
    public static String bufferedReader2String(BufferedReader reader) throws IOException {
        StringBuffer buf = new StringBuffer();
        String line = null;
        while( (line = reader.readLine()) != null) {
            buf.append(line);
            buf.append("\r\n");
        }
        return buf.toString();
    }
    /**
     * �������<br/>
     * ע��:���ر���Ҫ���д���
     * @param out
     * @param data
     * @param len
     * @throws IOException
     */
    public static void doOutput(OutputStream out, byte[] data, int len)
            throws IOException {
        int dataLen = data.length;
        int off = 0;
        while (off < data.length) {
            if (len >= dataLen) {
                out.write(data, off, dataLen);
                off += dataLen;
            } else {
                out.write(data, off, len);
                off += len;
                dataLen -= len;
            }
            // ˢ�»�����
            out.flush();
        }
    }
    /**
     * ��ȡSSLContext
     * @param trustFile
     * @param trustPasswd
     * @param keyFile
     * @param keyPasswd
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     * @throws IOException
     * @throws CertificateException
     * @throws UnrecoverableKeyException
     * @throws KeyManagementException
     */
    public static SSLContext getSSLContext(
            FileInputStream trustFileInputStream, String trustPasswd,
            FileInputStream keyFileInputStream, String keyPasswd)
            throws NoSuchAlgorithmException, KeyStoreException,
            CertificateException, IOException, UnrecoverableKeyException,
            KeyManagementException {
        // ca
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(HttpClientUtil.SunX509);
        KeyStore trustKeyStore = KeyStore.getInstance(HttpClientUtil.JKS);
        trustKeyStore.load(trustFileInputStream, HttpClientUtil
                .str2CharArray(trustPasswd));
        tmf.init(trustKeyStore);
        final char[] kp = HttpClientUtil.str2CharArray(keyPasswd);
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(HttpClientUtil.SunX509);
        KeyStore ks = KeyStore.getInstance(HttpClientUtil.PKCS12);
        ks.load(keyFileInputStream, kp);
        kmf.init(ks, kp);
        SecureRandom rand = new SecureRandom();
        SSLContext ctx = SSLContext.getInstance(HttpClientUtil.TLS);
        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), rand);
        return ctx;
    }
    /**
     * ��ȡCA֤����Ϣ
     * @param cafile CA֤���ļ�
     * @return Certificate
     * @throws CertificateException
     * @throws IOException
     */
    public static Certificate getCertificate(File cafile)
            throws CertificateException, IOException {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        FileInputStream in = new FileInputStream(cafile);
        Certificate cert = cf.generateCertificate(in);
        in.close();
        return cert;
    }
    /**
     * �ַ�ת����char����
     * @param str
     * @return char[]
     */
    public static char[] str2CharArray(String str) {
        if(null == str) return null;
        return str.toCharArray();
    }
    /**
     * �洢ca֤���JKS��ʽ
     * @param cert
     * @param alias
     * @param password
     * @param out
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     * @throws IOException
     */
    public static void storeCACert(Certificate cert, String alias,
            String password, OutputStream out) throws KeyStoreException,
            NoSuchAlgorithmException, CertificateException, IOException {
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(null, null);
        ks.setCertificateEntry(alias, cert);
        // store keystore
        ks.store(out, HttpClientUtil.str2CharArray(password));
    }
    public static InputStream String2Inputstream(String str) {
        return new ByteArrayInputStream(str.getBytes());
    }
    /**
     * InputStreamת����Byte
     * ע��:���ر���Ҫ���д���
     * @param in
     * @return byte
     * @throws Exception
     */
    public static byte[] InputStreamTOByte(InputStream in) throws IOException{
        int BUFFER_SIZE = 4096;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;
        while((count = in.read(data,0,BUFFER_SIZE)) != -1)
            outStream.write(data, 0, count);
        data = null;
        byte[] outByte = outStream.toByteArray();
        outStream.close();
        return outByte;
    }
    /**
     * InputStreamת����String
     * ע��:���ر���Ҫ���д���
     * @param in
     * @param encoding ����
     * @return String
     * @throws Exception
     */
    public static String InputStreamTOString(InputStream in,String encoding) throws IOException{
        return new String(InputStreamTOByte(in),encoding);
    }
}
hx_common/src/main/java/com/hx/mp/util/HttpUtil.java
New file
@@ -0,0 +1,31 @@
package com.hx.mp.util;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
public class HttpUtil {
    /**
     * 发送post请求
     *
     * @param url
     *            请求地址
     * @param outputEntity
     *            发送内容
     * @param isLoadCert
     *            是否加载证书
     */
    public static CloseableHttpResponse Post(String url, String outputEntity, boolean isLoadCert, String certPath, String mchId) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(new StringEntity(outputEntity, "UTF-8"));
        if (isLoadCert) {
            // 加载含有证书的http请求
            return HttpClients.custom().setSSLSocketFactory(CertUtil.initCert(certPath, mchId)).build().execute(httpPost);
        } else {
            return HttpClients.custom().build().execute(httpPost);
        }
    }
}
hx_common/src/main/java/com/hx/mp/util/HttpXmlUtils.java
New file
@@ -0,0 +1,63 @@
package com.hx.mp.util;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;
public class HttpXmlUtils {
    @SuppressWarnings("rawtypes")
    public static String transferXml(SortedMap<Object, Object> parameters) {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("xml");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            Element ToUserName = root.addElement(k);
            ToUserName.addText(v);
        }
        String queryString = document.asXML();// 转为String
        queryString = queryString.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "").trim();
        // System.out.println("企业端付款参数:"+queryString);
        return queryString;
    }
    @SuppressWarnings("unchecked")
    public static Map<String, String> parseRefundXml(String refundXml) throws JDOMException, IOException {
        StringReader read = new StringReader(refundXml);
        // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
        InputSource source = new InputSource(read);
        // 创建一个新的SAXBuilder
        SAXBuilder sb = new SAXBuilder();
        // 通过输入源构造一个Document
        Document doc;
        doc = (Document) sb.build(source);
        Element root = doc.getRootElement();// 指向根节点
        List<Element> list = root.elements();
        Map<String, String> refundOrderMap = new HashMap<String, String>();
        if (list != null && list.size() > 0) {
            for (Element element : list) {
                refundOrderMap.put(element.getName(), element.getText());
            }
            return refundOrderMap;
        }
        return null;
    }
}
hx_common/src/main/java/com/hx/mp/util/MD5Util.java
New file
@@ -0,0 +1,43 @@
package com.hx.mp.util;
import java.security.MessageDigest;
public class MD5Util {
    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));
        return resultSb.toString();
    }
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }
    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }
    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}
hx_common/src/main/java/com/hx/mp/util/MPWeixinBaseUtil.java
New file
@@ -0,0 +1,842 @@
package com.hx.mp.util;
import com.hx.util.OSSUtil;
import com.hx.util.SimpleTool;
import com.hx.util.StringUtils;
import com.hz.util.http.HttpHzUtil;
import com.hz.util.http.dto.HttpHzResponse;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * 微信获取权限基本工具类
 * @author ChenJiaHe
 * @Date 2020-07-14
 */
@Component
public class MPWeixinBaseUtil {
    // 类型
    private static final String GRANT_TYPE = "client_credential";
    /**获取access_token链接*/
    private static final String GETACCESS_TOKENURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=";
    /**通过code获取小程序信息链接*/
    private static final String JSCODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?";
    /**发送订阅消息通知链接*/
    private static final String SEND_SUBSCRIBE_MESSAGE = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
    /**生成小程序二维码地址(方形)*/
    public static final String MAKE_TWOCODE_SQUARE_URL = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=";
    /**生成小程序二维码地址(圆形)*/
    public static final String MAKE_TWOCODE_ROUND_URL = "https://api.weixin.qq.com/wxa/getwxacode?access_token={0}";
    /**生成无限二维码*/
    public static final String URL_UNLIMIT_SQUARE = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={0}";
    /**获取小程序订阅个人模板列表*/
    private static final String GET_APP_TEMPLATE = "https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate?access_token=";
    /**获取公众号模板列表*/
    private static final String GET_GZH_TEMPLATE = "https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=";
    //////////////////////////////////////////////////
    /** (小程序)通过code换取网页授权access_token/如果是snsapi_base模式的授权,这里就可以拿到openId了 ***/
    public static JSONObject getJscode2session(String appid,String secret,String code) {
        return HttpURLUtil(JSCODE2SESSION_URL+"appid="+appid+"&secret="+secret
                +"&grant_type=authorization_code&js_code=" + code,null);
    }
    /**发送订阅消息通知**/
    public static JSONObject sendSubscribeMessage(String data,String accessToken){
        return HttpURLUtil(SEND_SUBSCRIBE_MESSAGE+accessToken,data);
    }
    /** 获取access_token */
    public static JSONObject getAccessToken(String appid,String secret) throws Exception {
        String access_token;
        // 通过WX接口获取access_token
        JSONObject obj = getApplication_Access_tokenForUrl(appid,secret);
        return obj;
    }
    /** 从weixin接口获取Access_token **/
    public static JSONObject getApplication_Access_tokenForUrl(String appid,String secret) {
        return HttpURLUtil(GETACCESS_TOKENURL+GRANT_TYPE +"&appid="+appid +"&secret="+secret,null);
    }
    /**生成无限二维码,并上传到OSS*/
    public static String createUnlimitQrCode(String at, String scene, String page, int width, boolean autoColor,
                                             JSONObject lineColor, boolean isHyaline, String fileName, String keyId,
                                             String keySecret, String endPoint, String bucket)
    {
        String imgUrl = null;
        InputStream in = null;
        HttpURLConnection conn = null;
        try {
            //生成发送数据
            JSONObject obj = new JSONObject();
            obj.put("scene", scene);
            obj.put("width", width);
            obj.put("page", page);
            obj.put("auto_color", autoColor);
            obj.put("line_color", lineColor);
            obj.put("is_hyaline", isHyaline);
            // 创建url资源
            URL url = new URL(StringUtils.format(URL_UNLIMIT_SQUARE, at));
            // 建立http连接
            conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("contentType", "application/json");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write((obj.toString()).getBytes());
            out.flush();
            out.close();
            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                // 请求返回的数据
                in = conn.getInputStream();
                imgUrl = OSSUtil.uploadImg(fileName, in, keyId, keySecret, endPoint, bucket);
                conn.disconnect();
                conn = null;
            }
            if (in != null) {
                in.close();
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }catch (Exception e)
        {
            e.printStackTrace();
            if (in != null) {
                try {
                    in.close();
                }catch (Exception ep)
                {
                    ep.printStackTrace();
                }
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return imgUrl;
    }
    /**生成有限二维码,返回临时文
     * @param at 微信token
     * @param page 跳转链接
     * @param width 宽度
     * @param autoColor 默认false
     * @param lineColor 默认null
     * @param isHyaline 默认false
     * @return
     */
    public static File createLimitedQrCode(String at, String page, int width, boolean autoColor,
                                           JSONObject lineColor, boolean isHyaline) {
        String imgUrl = null;
        InputStream in = null;
        HttpURLConnection conn = null;
        //创建临时文件
        File file = null;
        try {
            file = File.createTempFile("temp", ".jpg");
            //生成发送数据
            JSONObject obj = new JSONObject();
            obj.put("width", width);
            obj.put("path", page);
            obj.put("auto_color", autoColor);
            obj.put("line_color", lineColor);
            obj.put("is_hyaline", isHyaline);
            // 创建url资源
            URL url = new URL(StringUtils.format(MAKE_TWOCODE_ROUND_URL, at));
            // 建立http连接
            conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("contentType", "application/json");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write((obj.toString()).getBytes());
            out.flush();
            out.close();
            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                // 请求返回的数据
                in = conn.getInputStream();
                //输入到临时文件
                /*OutputStream os = new FileOutputStream(file);
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = in.read(buffer, 0, 8192)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }*/
                FileUtils.copyInputStreamToFile(in, file);
                conn.disconnect();
                conn = null;
            }
            if (in != null) {
                in.close();
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }catch (Exception e) {
            e.printStackTrace();
            if (in != null) {
                try {
                    in.close();
                }catch (Exception ep) {
                    ep.printStackTrace();
                }
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }finally {
            if(file != null){
                file.deleteOnExit();
            }
        }
        return file;
    }
    /**生成有限二维码,返回临时文
     * @param at 微信token
     * @param page 跳转链接
     * @param width 宽度
     * @param autoColor 默认false
     * @param lineColor 默认null
     * @param isHyaline 默认false
     * @param envVersion 要打开的小程序版本。正式版为 release,体验版为 trial,开发版为 develop
     * @return
     */
    public static File createLimitedQrCode(String at, String page, int width, boolean autoColor,
                                           JSONObject lineColor, boolean isHyaline,String envVersion) {
        String imgUrl = null;
        InputStream in = null;
        HttpURLConnection conn = null;
        //创建临时文件
        File file = null;
        try {
            file = File.createTempFile("temp", ".jpg");
            //生成发送数据
            JSONObject obj = new JSONObject();
            obj.put("width", width);
            obj.put("path", page);
            obj.put("auto_color", autoColor);
            obj.put("line_color", lineColor);
            obj.put("is_hyaline", isHyaline);
            obj.put("env_version", envVersion);
            // 创建url资源
            URL url = new URL(StringUtils.format(MAKE_TWOCODE_ROUND_URL, at));
            // 建立http连接
            conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("contentType", "application/json");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write((obj.toString()).getBytes());
            out.flush();
            out.close();
            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                // 请求返回的数据
                in = conn.getInputStream();
                //输入到临时文件
                /*OutputStream os = new FileOutputStream(file);
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = in.read(buffer, 0, 8192)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }*/
                FileUtils.copyInputStreamToFile(in, file);
                conn.disconnect();
                conn = null;
            }
            if (in != null) {
                in.close();
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }catch (Exception e) {
            e.printStackTrace();
            if (in != null) {
                try {
                    in.close();
                }catch (Exception ep) {
                    ep.printStackTrace();
                }
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }finally {
            if(file != null){
                file.deleteOnExit();
            }
        }
        return file;
    }
    /**生成无限二维码,返回临时文
     * @param at 微信token
     * @param scene 参数,只能32位,最好不要中文
     * @param page 跳转链接
     * @param width 宽度
     * @param autoColor 默认false
     * @param lineColor 默认null
     * @param isHyaline 默认false
     * @return
     */
    public static File createUnlimitQrCode(String at, String scene, String page, int width, boolean autoColor,
                                             JSONObject lineColor, boolean isHyaline) throws IOException {
        String imgUrl = null;
        InputStream in = null;
        HttpURLConnection conn = null;
        //创建临时文件
        File file = File.createTempFile("temp", ".jpg");
        try {
            //生成发送数据
            JSONObject obj = new JSONObject();
            obj.put("scene", scene);
            obj.put("width", width);
            obj.put("page", page);
            obj.put("auto_color", autoColor);
            obj.put("line_color", lineColor);
            obj.put("is_hyaline", isHyaline);
            // 创建url资源
            URL url = new URL(StringUtils.format(URL_UNLIMIT_SQUARE, at));
            // 建立http连接
            conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("contentType", "application/json");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write((obj.toString()).getBytes());
            out.flush();
            out.close();
            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                // 请求返回的数据
                in = conn.getInputStream();
                //输入到临时文件
                /*OutputStream os = new FileOutputStream(file);
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = in.read(buffer, 0, 8192)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }*/
                FileUtils.copyInputStreamToFile(in, file);
                conn.disconnect();
                conn = null;
            }
            if (in != null) {
                in.close();
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }catch (Exception e) {
            e.printStackTrace();
            if (in != null) {
                try {
                    in.close();
                }catch (Exception ep) {
                    ep.printStackTrace();
                }
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }finally {
            file.deleteOnExit();
        }
        return file;
    }
    /**生成小程序二维码工具(方形)
     * path 二维码跳转链接
     * width 二维码宽度,默认是430
     * saveUrl 保存图片的全路径
     * seeUrl 显示图片路径
     * appid 小程序配置
     * secret 小程序配置
     * return 二维码显示图片链接
     * @throws Exception
     * */
    public static String twoCodeImgSquare(String at, String path,Integer width,String saveUrl,
                                          String seeUrl,String appid,String secret) throws Exception {
        if(!SimpleTool.checkNotNull(width)) {
            width = 430;
        }
        //生成发送数据
        JSONObject obj = new JSONObject();
        obj.put("path", path);
        obj.put("width", width);
        //二维码图片路径
        String codeUrl = "";
        codeUrl = HttpURLUtilMakeCodeImg(MAKE_TWOCODE_SQUARE_URL+at,obj,saveUrl,seeUrl);
        if(SimpleTool.checkNotNull(codeUrl)){
            if(!codeUrl.startsWith("/")){
                codeUrl = "/"+codeUrl;
            }
        }
        return codeUrl;
    }
    public static String twoCodeImgSquare(String at, String path,Integer width, String fileName, String keyId,
                                          String keySecret, String endPoint, String bucket) throws Exception {
        if(!SimpleTool.checkNotNull(width)) {
            width = 430;
        }
        //生成发送数据
        JSONObject obj = new JSONObject();
        obj.put("path", path);
        obj.put("width", width);
        String imgUrl = null;
        InputStream in = null;
        HttpURLConnection conn = null;
        try {
            // 创建url资源
            URL url = new URL(MAKE_TWOCODE_SQUARE_URL + at);
            // 建立http连接
            conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("contentType", "application/json");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write((obj.toString()).getBytes());
            out.flush();
            out.close();
            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                // 请求返回的数据
                in = conn.getInputStream();
                imgUrl = OSSUtil.uploadImg(fileName, in, keyId, keySecret, endPoint, bucket);
                conn.disconnect();
                conn = null;
            }
            if (in != null) {
                in.close();
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }catch (Exception e)
        {
            e.printStackTrace();
            if (in != null) {
                try {
                    in.close();
                }catch (Exception ep)
                {
                    ep.printStackTrace();
                }
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return imgUrl;
    }
    /** 生成二维码的图片 返回图片路径
     * urlx 执行链接
     * objx 数据
     * saveUrl 保存图片路径
     * seeUrl 显示图片路径
     *
     *  **/
    public static String HttpURLUtilMakeCodeImg(String urlx,JSONObject objx,String saveUrl,String seeUrl) throws IOException {
        String realpath = null;
        // 创建url资源
        URL url = new URL(urlx);
        // 建立http连接
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        // 设置允许输出
        conn.setDoOutput(true);
        conn.setDoInput(true);
        // 设置不用缓存
        conn.setUseCaches(false);
        // 设置传递方式
        conn.setRequestMethod("POST");
        // 设置维持长连接
        conn.setRequestProperty("Connection", "Keep-Alive");
        // 设置文件字符集:
        conn.setRequestProperty("Charset", "UTF-8");
        // 转换为字节数组
        // byte[] data = (objx.toString()).getBytes();
        // 设置文件长度
        // conn.setRequestProperty("Content-Length",String.valueOf(data.length));
        // 设置文件类型:
        conn.setRequestProperty("contentType", "application/json");
        // 开始连接请求
        conn.connect();
        OutputStream out = conn.getOutputStream();
        // 写入请求的字符串
        out.write((objx.toString()).getBytes());
        out.flush();
        out.close();
        // 请求返回的状态
        if (conn.getResponseCode() == 200) {
            System.out.println("连接成功");
            // 请求返回的数据
            InputStream in = conn.getInputStream();
            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            byte[] temp = new byte[1024];
            int rc = 0;
            while ((rc = in.read(temp, 0, 100)) > 0) {
                swapStream.write(temp, 0, rc);
            }
            byte[] buffer2 = swapStream.toByteArray();
            String base64 = Base64.encodeBase64String(buffer2);
            //生成名称
            java.util.Random r=new java.util.Random();
            StringBuilder str=new StringBuilder();//定义变长字符串
            for(int i=0;i<8;i++){
                str.append(r.nextInt(10));
            }
            Date date = new Date();
            SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
            String imgName = sf.format(date);
            imgName = imgName+str.toString();
            //文件保存位置
            File saveDir = new File(saveUrl);
            if(!saveDir.exists()){
                saveDir.mkdir();
            }
            File file = new File(saveDir+"/"+imgName+".png");
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(buffer2);
            if(fos!=null){
                fos.close();
            }
            if(in!=null){
                in.close();
            }
            realpath = seeUrl+"/"+imgName+".png";
        } else {
            System.out.println("no++");
        }
        return realpath;
    }
    /** 请求http协议 获取信息工具 **/
    private static JSONObject HttpURLUtil(String url,String data) {
        HttpURLConnection con = null;
        URL u;
        String wxMsgXml;
        JSONObject obj;
        try {
            u = new URL(url);
            con = (HttpURLConnection) u.openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setReadTimeout(5000);
            con.setRequestProperty("Charset", "UTF-8");
            con.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            if (data != null) {
                OutputStream os = con.getOutputStream();
                os.write(data.getBytes("utf-8"));
            }
            if (con.getResponseCode() != 200)
                throw new RuntimeException("请求url失败");
            // 读取返回内容
            wxMsgXml = IOUtils.toString(con.getInputStream(), StandardCharsets.UTF_8);
            // 判断返回参数是否正确/成功
            obj = JSONObject.fromObject(wxMsgXml);
            // System.out.println("HttpURLUtil:"+wxMsgXml);
        } catch (Exception e) {
            e.printStackTrace();
            obj = new JSONObject();
            try {
                obj.put("status", 1);
                obj.put("errMsg", e.getMessage());
            } catch (JSONException e1) {
                e1.printStackTrace();
            }
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        return obj;
    }
    /**生成无限二维码,返回临时文
     * @param at 微信token
     * @param scene 参数,只能32位,最好不要中文
     * @param page 跳转链接
     * @param width 宽度
     * @param autoColor 默认false
     * @param lineColor 默认null
     * @param isHyaline 默认false
     * @return
     */
    public static File createUnlimitQrCode(String at, String scene, String page, int width, boolean autoColor,
                                           JSONObject lineColor, boolean isHyaline, String env_version) throws IOException {
        String imgUrl = null;
        InputStream in = null;
        HttpURLConnection conn = null;
        //创建临时文件
        File file = File.createTempFile("temp", ".jpg");
        try {
            //生成发送数据
            JSONObject obj = new JSONObject();
            obj.put("scene", scene);
            obj.put("width", width);
            obj.put("page", page);
            obj.put("auto_color", autoColor);
            obj.put("line_color", lineColor);
            obj.put("is_hyaline", isHyaline);
            obj.put("env_version", env_version);
            //体验版时,可不检查页面是否存在
            if("trial".equals(env_version)){
                obj.put("check_path", false);
            }
            // 创建url资源
            URL url = new URL(StringUtils.format(URL_UNLIMIT_SQUARE, at));
            // 建立http连接
            conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("contentType", "application/json");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write((obj.toString()).getBytes());
            out.flush();
            out.close();
            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                // 请求返回的数据
                in = conn.getInputStream();
                //输入到临时文件
                /*OutputStream os = new FileOutputStream(file);
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = in.read(buffer, 0, 8192)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }*/
                FileUtils.copyInputStreamToFile(in, file);
                conn.disconnect();
                conn = null;
            }
            if (in != null) {
                in.close();
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }catch (Exception e) {
            e.printStackTrace();
            if (in != null) {
                try {
                    in.close();
                }catch (Exception ep) {
                    ep.printStackTrace();
                }
                in = null;
            }
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }finally {
            file.deleteOnExit();
        }
        return file;
    }
    /**
     * 获取小程序订阅模板
     * @param accessToken token
     * **/
    public static HttpHzResponse appTemplateList(String accessToken) {
        return HttpHzUtil.HttpURLUtilJson(GET_APP_TEMPLATE + accessToken, null,null,null,"GET",null);
    }
    /**
     * 公众号订阅模板
     * @param accessToken token
     * **/
    public static HttpHzResponse gzhTemplateList(String accessToken) {
        return HttpHzUtil.HttpURLUtilJson(GET_GZH_TEMPLATE+accessToken, null,null,null,"GET",null);
    }
}
hx_common/src/main/java/com/hx/mp/util/MpUtil.java
New file
@@ -0,0 +1,420 @@
package com.hx.mp.util;
import com.hx.util.HttpMethodUtil;
import com.hx.util.StringUtils;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * 微信小程序工具类
 */
public class MpUtil {
    /** 请求access_token */
    public static final String URL_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
    /** 请求服务器IP地址 */
    public static final String URL_SERVER_ADDR = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=";
    /** 微信js的code换去sessionKey */
    public static final String JSCODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&grant_type=authorization_code&js_code=";
    /** 请求小程序码 **/
    public static final String URL_WXACODE = "https://api.weixin.qq.com/wxa/getwxacode?access_token=";
    /** 请求小程序码-无数量限制 **/
    public static final String URL_WXACODEUNLIMIT = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=";
    /** 请求小程序二维码 */
    public static final String URL_QRCODE = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=";
    /** 发模版消息 */
    public static final String URL_SEND_TEMP_MSG = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=";
    /** 设置发票授权字段 */
    public static final String URL_SET_TICKET_FIELD = "https://api.weixin.qq.com/card/invoice/setbizattr?action=set_auth_field&access_token=";
    /** 获取发票ticket */
    public static final String URL_GET_TICKET_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card&access_token=";
    /** 获取发票授权页链接 */
    public static final String URL_GET_TICKET_AUTH_LINK = "https://api.weixin.qq.com/card/invoice/getauthurl?access_token=";
    /** 查询发票授权字段 */
    public static final String URL_GET_AUTH_FIELD = "https://api.weixin.qq.com/card/invoice/getauthdata?access_token=";
    /** 设置 支付后开发票 */
    public static final String URL_SET_PAY_INVOICE = "https://api.weixin.qq.com/card/invoice/setbizattr?action=set_pay_mch&access_token=";
    /** 查询支付后开发票 */
    public static final String URL_GET_PAY_INVOICE = "https://api.weixin.qq.com/card/invoice/setbizattr?action=get_pay_mch&access_token=";
    /** 发送客服消息 */
    public static final String URL_SEND_KF_MSG = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=";
    /*************************************************
     * 小程序
     *************************/
    /** 利用code换取sessionKey */
    public static JSONObject jsCode2session(String code, String appId, String appSecret) {
        JSONObject obj = new JSONObject();
        String url = StringUtils.format(JSCODE2SESSION_URL, appId, appSecret) + code;
        obj = HttpURLUtil(url, null);
        return obj;
    }
    /** 获取小程序二维码图片 */
    public static String getQrCode(String accessToken, String jsonParam)
            throws Exception {
        JSONObject obj = HttpURLUtilJson(URL_QRCODE + accessToken, jsonParam);
        String qrStr = obj.optString("data");
        return qrStr;
    }
    /** 从weixin接口获取Access_token **/
    public static JSONObject getApplication_Access_tokenForUrl(String appId, String appSecret)
            throws Exception {
        String url = MessageFormat.format(URL_ACCESS_TOKEN, appId, appSecret);
        JSONObject obj = HttpURLUtil(url, null);
        return obj;
    }
    /** 请求http协议 获取信息工具 **/
    public static InputStream HttpURLUtilStream(String url, String data) {
        HttpURLConnection con = null;
        URL u = null;
        try {
            u = new URL(url);
            con = (HttpURLConnection) u.openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setReadTimeout(200000);
            con.setRequestProperty("Charset", "UTF-8");
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            if (data != null) {
                OutputStream os = con.getOutputStream();
                os.write(data.getBytes("utf-8"));
            }
            if (con.getResponseCode() != 200)
                throw new RuntimeException("请求url失败");
            return con.getInputStream();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        return null;
    }
    /** 获取二维码图片 **/
    public static JSONObject HttpURLUtilJson(String urlx, String objx) {
        JSONObject jo = new JSONObject();
        try {
            // 创建url资源
            URL url = new URL(urlx);
            // 建立http连接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置允许输出
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 设置不用缓存
            conn.setUseCaches(false);
            // 设置传递方式
            conn.setRequestMethod("POST");
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive");
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("contentType", "application/json");
            // 开始连接请求
            conn.connect();
            OutputStream out = conn.getOutputStream();
            // 写入请求的字符串
            out.write(objx.getBytes());
            out.flush();
            out.close();
            // 请求返回的状态
            if (conn.getResponseCode() == 200) {
                // 请求返回的数据
                InputStream in = conn.getInputStream();
                try {
                    ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
                    byte[] temp = new byte[1024];
                    int rc = 0;
                    while ((rc = in.read(temp, 0, 100)) > 0) {
                        swapStream.write(temp, 0, rc);
                    }
                    byte[] buffer = swapStream.toByteArray();
                    String base64 = Base64.encodeBase64String(buffer);
                    jo.put("data", base64);
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            } else {
                // System.out.println("no++");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return jo;
    }
    /** 请求http协议 获取信息工具 **/
    public static JSONObject HttpURLUtil(String url, String data) {
        HttpURLConnection con = null;
        URL u = null;
        String wxMsgXml = null;
        JSONObject obj = null;
        try {
            u = new URL(url);
            con = (HttpURLConnection) u.openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setReadTimeout(5000);
            con.setRequestProperty("Charset", "UTF-8");
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            if (data != null) {
                OutputStream os = con.getOutputStream();
                os.write(data.getBytes("utf-8"));
            }
            if (con.getResponseCode() != 200)
                throw new RuntimeException("请求url失败");
            // 读取返回内容
            wxMsgXml = IOUtils.toString(con.getInputStream(), "utf-8");
            obj = JSONObject.fromObject(wxMsgXml);
            // //System.out.println("HttpURLUtil:"+wxMsgXml);
        } catch (Exception e) {
            e.printStackTrace();
            obj = new JSONObject();
            try {
                obj.put("status", 1);
                obj.put("errMsg", e.getMessage());
            } catch (JSONException e1) {
                e1.printStackTrace();
            }
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        return obj;
    }
    /** 发送模版消息 **/
    public static JSONObject sendTempMsg(String accessToken, String jsonStr) {
        JSONObject obj = HttpURLUtil(URL_SEND_TEMP_MSG + accessToken, jsonStr);
        return obj;
    }
    public static Integer DateToTimestamp(Date time) {
        Timestamp ts = new Timestamp(time.getTime());
        return (int) ((ts.getTime()) / 1000);
    }
    /**
     * 发送链接客服消息
     *
     * @throws JSONException
     */
    public static String sendKfLinkMsg(String at, String openId, String title, String description, String url,
                                       String imgUrl) throws JSONException {
        String result = "fail";
        JSONObject obj = new JSONObject();
        obj.put("touser", openId);
        obj.put("msgtype", "link");
        JSONObject pObj = new JSONObject();
        pObj.put("title", title);
        pObj.put("description", description);
        pObj.put("url", url);
        pObj.put("thumb_url", imgUrl);
        obj.put("link", pObj);
        JSONObject rObj = HttpURLUtil(URL_SEND_KF_MSG + at, obj.toString());
        // System.out.println("rObj==="+rObj);
        if (rObj != null) {
            if (rObj.optInt("errcode", -1) == 0) {
                result = "suc";
            } else {
                result = rObj.optString("errmsg");
            }
        }
        rObj = null;
        obj = null;
        return result;
    }
    /**
     * 发送图片客户消息
     *
     * @param access_token
     *            access_token
     * @param toUser
     *            用户openid
     * @param media_id
     *            素材id
     * @return
     */
    public static String sendKfImageMsg(String access_token, String toUser, String media_id) {
        String result = "fail";
        try {
            JSONObject obj = new JSONObject();
            obj.put("touser", toUser);
            obj.put("msgtype", "image");
            JSONObject pObj = new JSONObject();
            pObj.put("media_id", media_id);
            obj.put("image", pObj);
            JSONObject rObj = HttpURLUtil(URL_SEND_KF_MSG + access_token, obj.toString());
            System.out.println("rObj==" + rObj.toString());
            if (rObj != null) {
                if (rObj.optInt("errcode", -1) == 0) {
                    result = "suc";
                } else {
                    result = rObj.optString("errmsg");
                }
            }
            rObj = null;
            obj = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 发送文本客户消息
     *
     * @param access_token
     *            access_token
     * @param toUser
     *            用户openid
     * @return
     */
    public static String sendKfTextMsg(String access_token, String toUser, String content) {
        String result = "fail";
        try {
            JSONObject obj = new JSONObject();
            obj.put("touser", toUser);
            obj.put("msgtype", "text");
            JSONObject pObj = new JSONObject();
            pObj.put("content", content);
            obj.put("text", pObj);
            JSONObject rObj = HttpURLUtil(URL_SEND_KF_MSG + access_token, obj.toString());
            if (rObj != null) {
                if (rObj.optInt("errcode", -1) == 0) {
                    result = "suc";
                } else {
                    result = rObj.optString("errmsg");
                }
            }
            rObj = null;
            obj = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /** 获取小程序码图片 */
    public static String getWXACode(String accessToken, String jsonParam, String path)
            throws Exception {
        JSONObject obj = HttpURLUtilJson(URL_WXACODE + accessToken, jsonParam);
        String qrStr = obj.optString("data");
        return qrStr;
    }
    /** 获取小程序码图片 */
    public static String getWXACodeUnlimit(String accessToken, String jsonParam, String path)
            throws Exception {
        JSONObject obj = HttpURLUtilJson(URL_WXACODEUNLIMIT + accessToken, jsonParam);
        String qrStr = obj.optString("data");
        return qrStr;
    }
    /**
     * 获取小程序链接
     * @param token 小程序token
     * @param path  小程序页面路径
     * @param query 传值参数
     * @param env_version
     * @return 要打开的小程序版本。正式版为 "release",体验版为"trial",开发版为"develop",仅在微信外打开时生效
     */
    public static String getAooLetUrl(String token, String path, String query, String env_version) {
        Map<String, Object> map = new HashMap<>();
        map.put("access_token", token);
        JSONObject data = new JSONObject();
        data.put("path", path);
        data.put("query", query);
        data.put("env_version", env_version);
        return HttpMethodUtil.HttpURLUtilJson("https://api.weixin.qq.com/wxa/generate_urllink", data.toString(), map, null, "POST");
    }
    /**
     * 公众号发送小程序卡片客户消息
     * @param access_token  access_token
     * @param toUser 用户openid
     * @param title 标题
     * @param appid 小程序appid
     * @param pagepath 跳转页面路径
     * @param thumb_media_id 缩略图/小程序卡片图片的媒体ID,小程序卡片图片建议大小为520*416
     * @return
     */
    public static String sendMpMsg(String access_token, String toUser, String title,String appid,String pagepath,String thumb_media_id) {
        String result = "fail";
        try {
            JSONObject obj = new JSONObject();
            obj.put("touser", toUser);
            obj.put("msgtype", "miniprogrampage");
            JSONObject pObj = new JSONObject();
            pObj.put("title", title);
            pObj.put("appid", appid);
            pObj.put("pagepath", pagepath);
            pObj.put("thumb_media_id", thumb_media_id);
            obj.put("miniprogrampage", pObj);
            JSONObject rObj = HttpURLUtil(URL_SEND_KF_MSG + access_token, obj.toString());
            if (rObj != null) {
                if (rObj.optInt("errcode", -1) == 0) {
                    result = "suc";
                } else {
                    result = rObj.optString("errmsg");
                }
            }
            rObj = null;
            obj = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}
hx_common/src/main/java/com/hx/mp/util/RequestHandler.java
New file
@@ -0,0 +1,273 @@
package com.hx.mp.util;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * �������� ��������̳д��࣬��дcreateSign�������ɡ�
 *JX
 *linhan
 */
public class RequestHandler {
    /** ���url��ַ */
    private String gateUrl;
    /** ��Կ */
    private String key;
    /** ����IJ��� */
    @SuppressWarnings("rawtypes")
    private SortedMap parameters;
    /** debug��Ϣ */
    private String debugInfo;
    private HttpServletRequest request;
    private HttpServletResponse response;
    /**
     * ���캯��
     *
     * @param request
     * @param response
     */
    /*@SuppressWarnings("rawtypes")
    public RequestHandler(HttpServletRequest request,
            HttpServletResponse response) {
        this.request = request;
        this.response = response;
        this.gateUrl = "https://gw.tenpay.com/gateway/pay.htm";
        this.key = "";
        this.parameters = new TreeMap();
        this.debugInfo = "";
    }*/
    /**
     * ���캯��
     * @param request
     * @param response
     */
    public RequestHandler(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
        this.gateUrl = "https://gw.tenpay.com/gateway/pay.htm";
        this.key = "";
        this.parameters = new TreeMap();
        this.debugInfo = "";
    }
    /**
     * ��ʼ������
     */
    public void init() {
        // nothing to do
    }
    /**
     * ��ȡ��ڵ�ַ,�������ֵ
     */
    public String getGateUrl() {
        return gateUrl;
    }
    /**
     * ������ڵ�ַ,�������ֵ
     */
    public void setGateUrl(String gateUrl) {
        this.gateUrl = gateUrl;
    }
    /**
     * ��ȡ��Կ
     */
    public String getKey() {
        return key;
    }
    /**
     * 秘钥
     */
    public void setKey(String key) {
        this.key = key;
    }
    /**
     * ��ȡ����ֵ
     *
     * @param parameter
     *            �������
     * @return String
     */
    public String getParameter(String parameter) {
        String s = (String) this.parameters.get(parameter);
        return (null == s) ? "" : s;
    }
    /**
     * ���ò���ֵ
     *
     * @param parameter
     *            �������
     * @param parameterValue
     *            ����ֵ
     */
    @SuppressWarnings("unchecked")
    public void setParameter(String parameter, String parameterValue) {
        String v = "";
        if (null != parameterValue) {
            v = parameterValue.trim();
        }
        this.parameters.put(parameter, v);
    }
    /**
     * �������еIJ���
     *
     * @return SortedMap
     */
    @SuppressWarnings("rawtypes")
    public SortedMap getAllParameters() {
        return this.parameters;
    }
    /**
     * ��ȡdebug��Ϣ
     */
    public String getDebugInfo() {
        return debugInfo;
    }
    /**
     * ��ȡ����������URL
     *
     * @return String
     * @throws UnsupportedEncodingException
     */
    /*@SuppressWarnings("rawtypes")
    public String getRequestURL() throws UnsupportedEncodingException {
        this.createSign();
        StringBuffer sb = new StringBuffer();
        String enc = TenpayUtil.getCharacterEncoding(this.request,
                this.response);
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (!"spbill_create_ip".equals(k)) {
                sb.append(k + "=" + URLEncoder.encode(v, enc) + "&");
            } else {
                sb.append(k + "=" + v.replace(".", "%2E") + "&");
            }
        }
        // ȥ�����һ��&
        String reqPars = sb.substring(0, sb.lastIndexOf("&"));
        return this.getGateUrl() + "?" + reqPars;
    }*/
    /**
     * ��ȡ����������URL
     * @return String
     * @throws UnsupportedEncodingException
     */
    public String getRequestURL() throws UnsupportedEncodingException {
        this.createSign();
        StringBuffer sb = new StringBuffer();
        String enc = TenpayUtil.getCharacterEncoding(this.request, this.response);
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if(!"spbill_create_ip".equals(k)) {
                sb.append(k + "=" + URLEncoder.encode(v, enc) + "&");
            } else {
                sb.append(k + "=" + v.replace(".", "%2E") + "&");
            }
        }
        //ȥ�����һ��&
        String reqPars = sb.substring(0, sb.lastIndexOf("&"));
        return this.getGateUrl() + "?" + reqPars;
    }
    public void doSend() throws UnsupportedEncodingException, IOException {
        this.response.sendRedirect(this.getRequestURL());
    }
    /**
     * TODO 生成签名
     */
    @SuppressWarnings("rawtypes")
    public String createSign() {
        StringBuffer sb = new StringBuffer();
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k)
                    && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + this.getKey());
System.out.println("sb="+sb);
        String enc = TenpayUtil.getCharacterEncoding(this.request,
                this.response);
        String sign = MD5Util.MD5Encode(sb.toString(), enc).toUpperCase();
        this.setParameter("sign", sign);
        // debug��Ϣ
        this.setDebugInfo(sb.toString() + " => sign:" + sign);
        return sign;
    }
    /**
     * ����debug��Ϣ
     */
    protected void setDebugInfo(String debugInfo) {
        this.debugInfo = debugInfo;
    }
    protected HttpServletRequest getHttpServletRequest() {
        return this.request;
    }
    protected HttpServletResponse getHttpServletResponse() {
        return this.response;
    }
}
hx_common/src/main/java/com/hx/mp/util/ResponseHandler.java
New file
@@ -0,0 +1,225 @@
package com.hx.mp.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Ӧ������ Ӧ������̳д��࣬��дisTenpaySign�������ɡ�
 *JX
 *linhan
 */
public class ResponseHandler {
    /** ��Կ */
    private String key;
    /** Ӧ��IJ��� */
    @SuppressWarnings("rawtypes")
    private SortedMap parameters;
    /** debug��Ϣ */
    private String debugInfo;
    private HttpServletRequest request;
    private HttpServletResponse response;
    private String uriEncoding;
    /**
     * ���캯��
     *
     * @param request
     * @param response
     */
    @SuppressWarnings("rawtypes")
    public ResponseHandler(HttpServletRequest request,
            HttpServletResponse response) {
        this.request = request;
        this.response = response;
        this.key = "";
        this.parameters = new TreeMap();
        this.debugInfo = "";
        this.uriEncoding = "";
        Map m = this.request.getParameterMap();
        Iterator it = m.keySet().iterator();
        while (it.hasNext()) {
            String k = (String) it.next();
            String v = ((String[]) m.get(k))[0];
            this.setParameter(k, v);
        }
    }
    /**
     * ��ȡ��Կ
     */
    public String getKey() {
        return key;
    }
    /**
     * ������Կ
     */
    public void setKey(String key) {
        this.key = key;
    }
    /**
     * ��ȡ����ֵ
     *
     * @param parameter
     *            �������
     * @return String
     */
    public String getParameter(String parameter) {
        String s = (String) this.parameters.get(parameter);
        return (null == s) ? "" : s;
    }
    /**
     * ���ò���ֵ
     *
     * @param parameter
     *            �������
     * @param parameterValue
     *            ����ֵ
     */
    @SuppressWarnings("unchecked")
    public void setParameter(String parameter, String parameterValue) {
        String v = "";
        if (null != parameterValue) {
            v = parameterValue.trim();
        }
        this.parameters.put(parameter, v);
    }
    /**
     * �������еIJ���
     *
     * @return SortedMap
     */
    @SuppressWarnings("rawtypes")
    public SortedMap getAllParameters() {
        return this.parameters;
    }
    /**
     * �Ƿ�Ƹ�ͨǩ��,������:���������a-z����,������ֵ�IJ���μ�ǩ��
     *
     * @return boolean
     */
    @SuppressWarnings("rawtypes")
    public boolean isTenpaySign() {
        StringBuffer sb = new StringBuffer();
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + this.getKey());
        // ���ժҪ
        String enc = TenpayUtil.getCharacterEncoding(this.request,
                this.response);
        String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();
        String tenpaySign = this.getParameter("sign").toLowerCase();
        // debug��Ϣ
        this.setDebugInfo(sb.toString() + " => sign:" + sign + " tenpaySign:"
                + tenpaySign);
        return tenpaySign.equals(sign);
    }
    /**
     * ���ش������Ƹ�ͨ��������
     *
     * @param msg
     *            : Success or fail��
     * @throws IOException
     */
    public void sendToCFT(String msg) throws IOException {
        String strHtml = msg;
        PrintWriter out = this.getHttpServletResponse().getWriter();
        out.println(strHtml);
        out.flush();
        out.close();
    }
    /**
     * ��ȡuri����
     *
     * @return String
     */
    public String getUriEncoding() {
        return uriEncoding;
    }
    /**
     * ����uri����
     *
     * @param uriEncoding
     * @throws UnsupportedEncodingException
     */
    @SuppressWarnings("rawtypes")
    public void setUriEncoding(String uriEncoding)
            throws UnsupportedEncodingException {
        if (!"".equals(uriEncoding.trim())) {
            this.uriEncoding = uriEncoding;
            // ����ת��
            String enc = TenpayUtil.getCharacterEncoding(request, response);
            Iterator it = this.parameters.keySet().iterator();
            while (it.hasNext()) {
                String k = (String) it.next();
                String v = this.getParameter(k);
                v = new String(v.getBytes(uriEncoding.trim()), enc);
                this.setParameter(k, v);
            }
        }
    }
    /**
     * ��ȡdebug��Ϣ
     */
    public String getDebugInfo() {
        return debugInfo;
    }
    /**
     * ����debug��Ϣ
     */
    protected void setDebugInfo(String debugInfo) {
        this.debugInfo = debugInfo;
    }
    protected HttpServletRequest getHttpServletRequest() {
        return this.request;
    }
    protected HttpServletResponse getHttpServletResponse() {
        return this.response;
    }
}
hx_common/src/main/java/com/hx/mp/util/TenpayHttpClient.java
New file
@@ -0,0 +1,559 @@
package com.hx.mp.util;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
/**
 * �Ƹ�ͨhttp����https����ͨ�ſͻ���<br/>
 * ========================================================================<br/>
 * api˵����<br/>
 * setReqContent($reqContent),�����������ݣ�����post��get������get��ʽ�ṩ<br/>
 * getResContent(), ��ȡӦ������<br/>
 * setMethod(method),�������󷽷�,post����get<br/>
 * getErrInfo(),��ȡ������Ϣ<br/>
 * setCertInfo(certFile, certPasswd),����֤�飬˫��httpsʱ��Ҫʹ��<br/>
 * setCaInfo(caFile), ����CA����ʽδpem���������򲻼��<br/>
 * setTimeOut(timeOut)�� ���ó�ʱʱ�䣬��λ��<br/>
 * getResponseCode(), ȡ���ص�http״̬��<br/>
 * call(),������ýӿ�<br/>
 * getCharset()/setCharset(),�ַ����<br/>
 *
 * ========================================================================<br/>
 *
 */
public class TenpayHttpClient {
    private static final String USER_AGENT_VALUE =
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP)";
    private static final String JKS_CA_FILENAME =
        "tenpay_cacert.jks";
    private static final String JKS_CA_ALIAS = "tenpay";
    private static final String JKS_CA_PASSWORD = "";
    /** ca֤���ļ� */
    private File caFile;
    /** ֤���ļ� */
    private File certFile;
    /** ֤������ */
    private String certPasswd;
    /** �������ݣ�����post��get������get��ʽ�ṩ */
    private String reqContent;
    /** Ӧ������ */
    private String resContent;
    /** ���󷽷� */
    private String method;
    /** ������Ϣ */
    private String errInfo;
    /** ��ʱʱ��,����Ϊ��λ */
    private int timeOut;
    /** httpӦ����� */
    private int responseCode;
    /** �ַ���� */
    private String charset;
    private InputStream inputStream;
    private RequestHandler reqHandler;//方便取值所用(quan)
    /*public TenpayHttpClient() {
        this.caFile = null;
        this.certFile = null;
        this.certPasswd = "";
        this.reqContent = "";
        this.resContent = "";
        this.method = "POST";
        this.errInfo = "";
        this.timeOut = 30;//30��
        this.responseCode = 0;
        this.charset = "UTF-8";
        this.inputStream = null;
    }*/
    public TenpayHttpClient() {
        this.caFile = null;
        this.certFile = null;
        this.certPasswd = "";
        this.reqContent = "";
        this.resContent = "";
        this.method = "POST";
        this.errInfo = "";
        this.timeOut = 30;//30��
        this.responseCode = 0;
        this.charset = "UTF-8";
        this.inputStream = null;
    }
    /**
     * ����֤����Ϣ
     * @param certFile ֤���ļ�
     * @param certPasswd ֤������
     */
    public void setCertInfo(File certFile, String certPasswd) {
        this.certFile = certFile;
        this.certPasswd = certPasswd;
    }
    /**
     * ����ca
     * @param caFile
     */
    public void setCaInfo(File caFile) {
        this.caFile = caFile;
    }
    /**
     * ������������
     * @param reqContent ��������
     */
    public void setReqContent(String reqContent) {
        this.reqContent = reqContent;
    }
    /**
     * ��ȡ�������
     * @return String
     * @throws IOException
     */
    public String getResContent() {
        try {
            this.doResponse();
        } catch (IOException e) {
            this.errInfo = e.getMessage();
            //return "";
        }
        return this.resContent;
    }
    /**
     * �������󷽷�post����get
     * @param method ���󷽷�post/get
     */
    public void setMethod(String method) {
        this.method = method;
    }
    /**
     * ��ȡ������Ϣ
     * @return String
     */
    public String getErrInfo() {
        return this.errInfo;
    }
    /**
     * ���ó�ʱʱ��,����Ϊ��λ
     * @param timeOut ��ʱʱ��,����Ϊ��λ
     */
    public void setTimeOut(int timeOut) {
        this.timeOut = timeOut;
    }
    /**
     * ��ȡhttp״̬��
     * @return int
     */
    public int getResponseCode() {
        return this.responseCode;
    }
    /**
     * ִ��http���á�true:�ɹ� false:ʧ��
     * @return boolean
     */
/*    public boolean call() {
        boolean isRet = false;
        //http
        if(null == this.caFile && null == this.certFile) {
            System.out.println("没有CA");
            try {
                this.callHttp();
                isRet = true;
            } catch (IOException e) {
                this.errInfo = e.getMessage();
            }
            return isRet;
        }
        //https
        try {
            this.callHttps();
            isRet = true;
        } catch (UnrecoverableKeyException e) {
            this.errInfo = e.getMessage();
        } catch (KeyManagementException e) {
            this.errInfo = e.getMessage();
        } catch (CertificateException e) {
            this.errInfo = e.getMessage();
        } catch (KeyStoreException e) {
            this.errInfo = e.getMessage();
        } catch (NoSuchAlgorithmException e) {
            this.errInfo = e.getMessage();
        } catch (IOException e) {
            this.errInfo = e.getMessage();
        }
        return isRet;
    }*/
    /**
     * ִ��http���á�true:�ɹ� false:ʧ��
     * @return boolean
     */
    public boolean call() {
        boolean isRet = false;
        //http
        if(null == this.caFile && null == this.certFile) {
            System.out.println("没有CA");
            try {
                this.callHttp();
                isRet = true;
            } catch (IOException e) {
                this.errInfo = e.getMessage();
            }
            return isRet;
        }
        //https
        try {
            this.callHttps();
            isRet = true;
        } catch (UnrecoverableKeyException e) {
            this.errInfo = e.getMessage();
        } catch (KeyManagementException e) {
            this.errInfo = e.getMessage();
        } catch (CertificateException e) {
            this.errInfo = e.getMessage();
        } catch (KeyStoreException e) {
            this.errInfo = e.getMessage();
        } catch (NoSuchAlgorithmException e) {
            this.errInfo = e.getMessage();
        } catch (IOException e) {
            this.errInfo = e.getMessage();
        }
        return isRet;
    }
    protected void callHttp() throws IOException {
        if("POST".equals(this.method.toUpperCase())) {
            String url = HttpClientUtil.getURL(this.reqContent);
            System.out.println("tenpayHttpClient:url:"+url);
            //String queryString = HttpClientUtil.getQueryString(this.reqContent);
            //byte[] postData = queryString.getBytes(this.charset);
            String queryString = createXmlPosData();
            byte[] postData = queryString.getBytes(this.charset);
            this.httpPostMethod(url, postData);
            return ;
        }
        this.httpGetMethod(this.reqContent);
    }
    protected void callHttps() throws IOException, CertificateException,
            KeyStoreException, NoSuchAlgorithmException,
            UnrecoverableKeyException, KeyManagementException {
        // caĿ¼
        String caPath = this.caFile.getParent();
        System.out.println("caPath:"+caPath);
        File jksCAFile = new File(caPath + "/"
                + TenpayHttpClient.JKS_CA_FILENAME);
        if (!jksCAFile.isFile()) {
            X509Certificate cert = (X509Certificate) HttpClientUtil
                    .getCertificate(this.caFile);
            FileOutputStream out = new FileOutputStream(jksCAFile);
            // store jks file
            HttpClientUtil.storeCACert(cert, TenpayHttpClient.JKS_CA_ALIAS,
                    TenpayHttpClient.JKS_CA_PASSWORD, out);
            out.close();
        }
        FileInputStream trustStream = new FileInputStream(jksCAFile);
        FileInputStream keyStream = new FileInputStream(this.certFile);
        SSLContext sslContext = HttpClientUtil.getSSLContext(trustStream,
                TenpayHttpClient.JKS_CA_PASSWORD, keyStream, this.certPasswd);
        //�ر���
        keyStream.close();
        trustStream.close();
        if("POST".equals(this.method.toUpperCase())) {
            String url = HttpClientUtil.getURL(this.reqContent);
            //原本是直接参数转为字节数组的,现在组拼xml
            //String queryString = HttpClientUtil.getQueryString(this.reqContent);//获取链接下面的内容
            //byte[] postData = queryString.getBytes(this.charset);//把参数转为字节数组
            //先获取参数
            String queryString = createXmlPosData();
            byte[] postData = queryString.getBytes(this.charset);//把参数转为字节数组
            this.httpsPostMethod(url, postData, sslContext);
            return ;
        }
        this.httpsGetMethod(this.reqContent, sslContext);
    }
    /**
     * ��http post��ʽͨ��
     * @param url
     * @param postData
     * @throws IOException
     */
    protected void httpPostMethod(String url, byte[] postData)
            throws IOException {
        HttpURLConnection conn = HttpClientUtil.getHttpURLConnection(url);
        this.doPost(conn, postData);
    }
    /**
     * ��http get��ʽͨ��
     *
     * @param url
     * @throws IOException
     */
    protected void httpGetMethod(String url) throws IOException {
        HttpURLConnection httpConnection =
            HttpClientUtil.getHttpURLConnection(url);
        this.setHttpRequest(httpConnection);
        httpConnection.setRequestMethod("GET");
        this.responseCode = httpConnection.getResponseCode();
        this.inputStream = httpConnection.getInputStream();
    }
    /**
     * ��https get��ʽͨ��
     * @param url
     * @param sslContext
     * @throws IOException
     */
    protected void httpsGetMethod(String url, SSLContext sslContext)
            throws IOException {
        SSLSocketFactory sf = sslContext.getSocketFactory();
        HttpsURLConnection conn = HttpClientUtil.getHttpsURLConnection(url);
        conn.setSSLSocketFactory(sf);
        this.doGet(conn);
    }
    //提交https post 数据 s
    protected void httpsPostMethod(String url, byte[] postData,
            SSLContext sslContext) throws IOException {
        SSLSocketFactory sf = sslContext.getSocketFactory();
        HttpsURLConnection conn = HttpClientUtil.getHttpsURLConnection(url);
        conn.setSSLSocketFactory(sf);
        this.doPost(conn, postData);
    }
    /**
     * ����http����Ĭ������
     * @param httpConnection
     */
    protected void setHttpRequest(HttpURLConnection httpConnection) {
        //�������ӳ�ʱʱ��
        httpConnection.setConnectTimeout(this.timeOut * 1000);
        //User-Agent
        httpConnection.setRequestProperty("User-Agent",
                TenpayHttpClient.USER_AGENT_VALUE);
        //��ʹ�û���
        httpConnection.setUseCaches(false);
        //�����������
        httpConnection.setDoInput(true);
        httpConnection.setDoOutput(true);
    }
    /**
     * ����Ӧ��
     * @throws IOException
     */
    protected void doResponse() throws IOException {
        if(null == this.inputStream) {
            return;
        }
        //��ȡӦ������
        this.resContent=HttpClientUtil.InputStreamTOString(this.inputStream,this.charset);
    //    System.out.println("tenpayHttpClinet:385:"+resContent);
        //�ر�������
        this.inputStream.close();
    }
    /**
     * post��ʽ����
     * @param conn
     * @param postData
     * @throws IOException
     */
    protected void doPost(HttpURLConnection conn, byte[] postData)
            throws IOException {
        // ��post��ʽͨ��
        conn.setRequestMethod("POST");
        // ��������Ĭ������
        this.setHttpRequest(conn);
        // Content-Type
        conn.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded");
        BufferedOutputStream out = new BufferedOutputStream(conn
                .getOutputStream());
        final int len = 1024; // 1KB
        HttpClientUtil.doOutput(out, postData, len);
        // �ر���
        out.close();
        // ��ȡ��Ӧ����״̬��
        this.responseCode = conn.getResponseCode();
        // ��ȡӦ��������
        this.inputStream = conn.getInputStream();
    }
    /**
     * get��ʽ����
     * @param conn
     * @throws IOException
     */
    protected void doGet(HttpURLConnection conn) throws IOException {
        //��GET��ʽͨ��
        conn.setRequestMethod("GET");
        //��������Ĭ������
        this.setHttpRequest(conn);
        //��ȡ��Ӧ����״̬��
        this.responseCode = conn.getResponseCode();
        //��ȡӦ��������
        this.inputStream = conn.getInputStream();
    }
    public void setRequestHandler(RequestHandler reqHandler) {
        this.reqHandler = reqHandler;
    }
    //组建xml格式传递参数
    @SuppressWarnings({ "rawtypes", "unused" })
    public String createXmlPosData(){
        //先获取参数
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("xml");
        if(reqHandler==null)throw new RuntimeException("请先设入reqHandler");
        SortedMap parameters = reqHandler.getAllParameters();
        Set es = reqHandler.getAllParameters().entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            Element ToUserName = root.addElement(k);
            ToUserName.addText(v);
        }
        String queryString = document.asXML();//转为String
        queryString = queryString.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "").trim();
        System.out.println("xml:"+queryString);
        return queryString;
    }
}
hx_common/src/main/java/com/hx/mp/util/TenpayUtil.java
New file
@@ -0,0 +1,132 @@
package com.hx.mp.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TenpayUtil {
    /**
     * �Ѷ���ת�����ַ�
     * @param obj
     * @return String ת�����ַ�,������Ϊnull,�򷵻ؿ��ַ�.
     */
    public static String toString(Object obj) {
        if(obj == null)
            return "";
        return obj.toString();
    }
    /**
     * �Ѷ���ת��Ϊint��ֵ.
     *
     * @param obj
     *            �����ֵĶ���.
     * @return int ת�������ֵ,�Բ���ת���Ķ��󷵻�0��
     */
    public static int toInt(Object obj) {
        int a = 0;
        try {
            if (obj != null)
                a = Integer.parseInt(obj.toString());
        } catch (Exception e) {
        }
        return a;
    }
    /**
     * ��ȡ��ǰʱ�� yyyyMMddHHmmss
     * @return String
     */
    public static String getCurrTime() {
        Date now = new Date();
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String s = outFormat.format(now);
        return s;
    }
    /**
     * ��ȡ��ǰ���� yyyyMMdd
     * @param date
     * @return String
     */
    public static String formatDate(Date date) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        String strDate = formatter.format(date);
        return strDate;
    }
    /**
     * ȡ��һ��ָ�����ȴ�С�����������.
     *
     * @param length
     *            int �趨��ȡ�������ij��ȡ�lengthС��11
     * @return int ������ɵ������
     */
    public static int buildRandom(int length) {
        int num = 1;
        double random = Math.random();
        if (random < 0.1) {
            random = random + 0.1;
        }
        for (int i = 0; i < length; i++) {
            num = num * 10;
        }
        return (int) ((random * num));
    }
    /**
     * ��ȡ�����ַ�
     * @param request
     * @param response
     * @return String
     */
    public static String getCharacterEncoding(HttpServletRequest request,
            HttpServletResponse response) {
        if(null == request || null == response) {
            return "utf-8";
        }
        String enc = request.getCharacterEncoding();
        if(null == enc || "".equals(enc)) {
            enc = response.getCharacterEncoding();
        }
        if(null == enc || "".equals(enc)) {
            enc = "utf-8";
        }
        return enc;
    }
    /**
     * ��ȡunixʱ�䣬��1970-01-01 00:00:00��ʼ������
     * @param date
     * @return long
     */
    public static long getUnixTime(Date date) {
        if( null == date ) {
            return 0;
        }
        return date.getTime()/1000;
    }
    /**
     * ʱ��ת�����ַ�
     * @param date ʱ��
     * @param formatType ��ʽ������
     * @return String
     */
    public static String date2String(Date date, String formatType) {
        SimpleDateFormat sdf = new SimpleDateFormat(formatType);
        return sdf.format(date);
    }
}
hx_common/src/main/java/com/hx/mp/util/WXPayUtil.java
New file
@@ -0,0 +1,622 @@
package com.hx.mp.util;
import com.hx.exception.ServiceException;
import com.hx.util.SimpleTool;
import com.hx.util.StringUtils;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.*;
/** 微信支付/退款
 * @author ChenJiaHe
 */
public class WXPayUtil {
    // 退款接口连接
    private static final String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
     /**查询订单链接*/
    @SuppressWarnings("unused")
    private static final String QUERY_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
    /**同意下单链接*/
    private static final String FIRST_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    // 企业付款
    private static final String CORP_PAY_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
    /** 企业付款*/
    public static JSONObject qdCorpPay(String appId, String orderNo, String certPath, String mchid, String mchKey, String openId, String payFee, String desc)
            throws Exception {
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("mch_appid", appId);
        parameters.put("mchid", mchid);
        parameters.put("partner_trade_no", orderNo);
        parameters.put("nonce_str", UUID.randomUUID().toString().substring(0, 30));
        parameters.put("openid", openId);
        parameters.put("check_name", "NO_CHECK");
        parameters.put("amount", payFee);
        parameters.put("spbill_create_ip", "8.8.8.8");
        parameters.put("desc", desc);
        String sign = WXSignUtils.createSign("UTF-8", parameters, mchKey);
        parameters.put("sign", sign);
        String xmlInfo = HttpXmlUtils.transferXml(parameters);
        JSONObject returnObj = new JSONObject();
        try {
            CloseableHttpResponse response = HttpUtil.Post(CORP_PAY_URL, xmlInfo, true, certPath, mchid);
            String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
            // System.out.println("渠道端企业付款:" + transfersXml);
            Map<String, String> transferMap = HttpXmlUtils.parseRefundXml(transfersXml);
            boolean bl = false;
            if (transferMap.size() > 0) {
                if (transferMap.get("return_code").equals("SUCCESS")) {
                    // 通讯成功
                    if (transferMap.get("result_code").equals("SUCCESS")) {
                        // 成功需要进行的逻辑操作
                        returnObj.put("status", "suc");
                    } else {
                        bl = true;
                        returnObj.put("status", "fail");
                        returnObj.put("errMsg", transferMap.get("err_code") + "|" + transferMap.get("err_code_des"));
                    }
                } else {
                    bl = true;
                    // 通讯不成功
                    returnObj.put("status", "fail");
                    returnObj.put("errMsg", transferMap.get("return_msg"));
                }
            } else {
                bl = true;
                returnObj.put("status", "fail");
                returnObj.put("errMsg", "返回为空");
            }
            if (bl) {
                System.out.println("企业付款失败:" + transfersXml);
            }
        } catch (Exception e) {
            e.printStackTrace();
            returnObj.put("status", "fail");
            returnObj.put("errMsg", e.getMessage());
        }
        return returnObj;
    }
    /**统一支付
     * @param request 方法获取
     * @param appId  小程序号
     * @param partner  商户号
     * @param key  秘钥
     * @param notifyUrl  回调链接
     * @param out_trade_no  订单号
     * @param body 商品描述
     * @param total_fee 支付金额
     * @param openid 用户openId
     * @param attach 附带数据包
     * @param notifyUrl 回调通知地址
     * @param trade_type 交易类型
     * @return JSON  status = "SUC"为成功
     */
    public static JSONObject unifiedPay(HttpServletRequest request,String appId,String partner,String key,String notifyUrl,String out_trade_no, String body, String total_fee, String openid,
            String attach,String trade_type) throws Exception {
        if (!SimpleTool.checkNotNull(notifyUrl)) {
            throw new ServiceException("支付功能故障!");
        }
        // 创建查询请求对象
        RequestHandler reqHandler = new RequestHandler(null, null);
        // 通信对象
        TenpayHttpClient httpClient = new TenpayHttpClient();
        // 应答对象
        ClientResponseHandler resHandler = new ClientResponseHandler();
        // -----------------------------
        // 设置请求参数
        // -----------------------------
        // reqHandler.init();
        reqHandler.setKey(key);
        reqHandler.setGateUrl(FIRST_ORDER_URL);// 请求URL
        // -----------------------------
        // 设置接口参数(sign后台自动生成)
        // -----------------------------
        reqHandler.setParameter("appid", appId); // 公众号/小程序
        reqHandler.setParameter("mch_id", partner); // 商户号
        reqHandler.setParameter("nonce_str", SimpleTool.getUUIDName().substring(0, 30));// 随机乱码
        reqHandler.setParameter("body", body);// 商品描述
        reqHandler.setParameter("out_trade_no", out_trade_no);// 商户订单号
        reqHandler.setParameter("total_fee", total_fee);// 总金额
        reqHandler.setParameter("spbill_create_ip", "8.8.8.8");// 终端IP
        reqHandler.setParameter("notify_url",notifyUrl);// 通知地址
        reqHandler.setParameter("trade_type", trade_type);// 交易类型
                                                          // JSAPI,NATIVE,APP
        reqHandler.setParameter("openid", openid);// openId
        reqHandler.setParameter("attach", attach);// 附带数据包
        // -----------------------------
        // 设置通信参数
        // -----------------------------
        // 设置请求返回的等待时间
        httpClient.setTimeOut(5);
        // 设置ca证书
        // httpClient.setCaInfo(new File(CA_PATH));
        // 设置个人(商户)证书
        // httpClient.setCertInfo(new File(CERT_PATH), CERT_PWD);
        // 设置发送类型POST
        httpClient.setMethod("POST");
        // 设置请求内容(生成sign)
        String requestUrl = reqHandler.getRequestURL();// 组拼https://www.baidu.com?a=x&b=xx
        httpClient.setReqContent(requestUrl);// https://www.baidu.com?a=x&b=xx
        String rescontent = "null";
        httpClient.setRequestHandler(reqHandler);// 把处理对象,像是参数各种东西都设置进去方便获取(quan)
        // 返回出去的对象(状态,错误原因,该操作相关信息(参数,返回值))
        JSONObject returnObj = new JSONObject();
        // 后台调用
        if (httpClient.call()) {
            System.out.println("统一下单,成功cll了::");
            // 设置结果参数
            rescontent = httpClient.getResContent();
            System.out.println("统一下单返回结果:" + rescontent);
            resHandler.setContent(rescontent);// 解析xml
            resHandler.setKey(key);
            // 获取返回参数
            String return_code = resHandler.getParameter("return_code");
            String return_msg = resHandler.getParameter("return_msg");
            // 判断签名及结果
            if (resHandler.isTenpaySign() && "SUCCESS".equals(return_code)) {
                String prepay_id = resHandler.getParameter("prepay_id");// 预支付交易会话标识
                String code_url = resHandler.getParameter("code_url");// 二维码链接
                String result_code = resHandler.getParameter("result_code");// 业务结果
                String appid = resHandler.getParameter("appid");// 公众账号ID
                String mch_id = resHandler.getParameter("mch_id");// 商户号
                String nonce_str = resHandler.getParameter("nonce_str");// 随机码
                String sign = resHandler.getParameter("sign");// 签名
                if (result_code.equals("SUCCESS")) {
                    returnObj.put("status", "suc");
                    returnObj.put("sign", sign);
                    returnObj.put("nonce_str", nonce_str);
                    returnObj.put("mch_id", mch_id);
                    returnObj.put("appid", appid);
                    returnObj.put("prepay_id", prepay_id);
                    returnObj.put("code_url", code_url);
                    returnObj.put("out_trade_no", out_trade_no);
                } else {
                    String errMsg = "[ERROR]result_code:" + resHandler.getParameter("result_code") + " err_code:"
                            + resHandler.getParameter("err_code") + "err_code_des:"
                            + resHandler.getParameter("err_code_des");
                    // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                    returnObj.put("status", "ERROR-C");
                    returnObj.put("errMsg", errMsg);
                }
            } else {
                String errMsg = "return_code:" + return_code + "err_code:" + resHandler.getParameter("err_code")
                        + " return_msg:" + return_msg;
                // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                returnObj.put("status", "ERROR-B");
                returnObj.put("errMsg", errMsg);
            }
        } else {
            // 有可能因为网络原因,请求已经处理,但未收到应答。
            returnObj.put("status", "ERROR-A");
            returnObj.put("errMsg", httpClient.getResponseCode() + ":" + httpClient.getErrInfo());
        }
        // 获取debug信息,建议把请求、应答内容、debug信息,通信返回码写入日志,方便定位问题
        String detail = "http res:" + httpClient.getResponseCode() + "," + httpClient.getErrInfo() + ";" + "req url:"
                + requestUrl + ";" + ";" + "req debug:" + reqHandler.getDebugInfo() + ";" + "res content:" + rescontent
                + ";" + "res debug:" + resHandler.getDebugInfo() + ";";
        returnObj.put("detail", detail);
        return returnObj;
    }
    /**统一支付(分账)
     * @param request 方法获取
     * @param appId  小程序号
     * @param partner  商户号
     * @param key  秘钥
     * @param notifyUrl  回调链接
     * @param out_trade_no  订单号
     * @param body 商品描述
     * @param total_fee 支付金额
     * @param openid 用户openId
     * @param attach 附带数据包
     * @param notifyUrl 回调通知地址
     * @param trade_type 交易类型
     * @param profit_sharing 是否分账:N不,Y是
     * @return JSON  status = "SUC"为成功
     */
    public static JSONObject unifiedPay(HttpServletRequest request,String appId,String partner,String key,String notifyUrl,String out_trade_no, String body, String total_fee, String openid,
                                        String attach,String trade_type,String profit_sharing) throws Exception {
        if (!SimpleTool.checkNotNull(notifyUrl)) {
            throw new ServiceException("支付功能故障!");
        }
        // 创建查询请求对象
        RequestHandler reqHandler = new RequestHandler(null, null);
        // 通信对象
        TenpayHttpClient httpClient = new TenpayHttpClient();
        // 应答对象
        ClientResponseHandler resHandler = new ClientResponseHandler();
        // -----------------------------
        // 设置请求参数
        // -----------------------------
        // reqHandler.init();
        reqHandler.setKey(key);
        reqHandler.setGateUrl(FIRST_ORDER_URL);// 请求URL
        // -----------------------------
        // 设置接口参数(sign后台自动生成)
        // -----------------------------
        reqHandler.setParameter("appid", appId); // 公众号/小程序
        reqHandler.setParameter("mch_id", partner); // 商户号
        reqHandler.setParameter("nonce_str", SimpleTool.getUUIDName().substring(0, 30));// 随机乱码
        reqHandler.setParameter("body", body);// 商品描述
        reqHandler.setParameter("out_trade_no", out_trade_no);// 商户订单号
        reqHandler.setParameter("total_fee", total_fee);// 总金额
        reqHandler.setParameter("spbill_create_ip", "8.8.8.8");// 终端IP
        reqHandler.setParameter("notify_url",notifyUrl);// 通知地址
        reqHandler.setParameter("trade_type", trade_type);// 交易类型
        //JSAPI,NATIVE,APP
        reqHandler.setParameter("openid", openid);// openId
        reqHandler.setParameter("attach", attach);// 附带数据包
        reqHandler.setParameter("profit_sharing", profit_sharing);// 附带数据包
        // -----------------------------
        // 设置通信参数
        // -----------------------------
        // 设置请求返回的等待时间
        httpClient.setTimeOut(5);
        // 设置ca证书
        // httpClient.setCaInfo(new File(CA_PATH));
        // 设置个人(商户)证书
        // httpClient.setCertInfo(new File(CERT_PATH), CERT_PWD);
        // 设置发送类型POST
        httpClient.setMethod("POST");
        // 设置请求内容(生成sign)
        String requestUrl = reqHandler.getRequestURL();// 组拼https://www.baidu.com?a=x&b=xx
        httpClient.setReqContent(requestUrl);// https://www.baidu.com?a=x&b=xx
        String rescontent = "null";
        httpClient.setRequestHandler(reqHandler);// 把处理对象,像是参数各种东西都设置进去方便获取(quan)
        // 返回出去的对象(状态,错误原因,该操作相关信息(参数,返回值))
        JSONObject returnObj = new JSONObject();
        // 后台调用
        if (httpClient.call()) {
            System.out.println("统一下单,成功cll了::");
            // 设置结果参数
            rescontent = httpClient.getResContent();
            System.out.println("统一下单返回结果:" + rescontent);
            resHandler.setContent(rescontent);// 解析xml
            resHandler.setKey(key);
            // 获取返回参数
            String return_code = resHandler.getParameter("return_code");
            String return_msg = resHandler.getParameter("return_msg");
            // 判断签名及结果
            if (resHandler.isTenpaySign() && "SUCCESS".equals(return_code)) {
                String prepay_id = resHandler.getParameter("prepay_id");// 预支付交易会话标识
                String code_url = resHandler.getParameter("code_url");// 二维码链接
                String result_code = resHandler.getParameter("result_code");// 业务结果
                String appid = resHandler.getParameter("appid");// 公众账号ID
                String mch_id = resHandler.getParameter("mch_id");// 商户号
                String nonce_str = resHandler.getParameter("nonce_str");// 随机码
                String sign = resHandler.getParameter("sign");// 签名
                if (result_code.equals("SUCCESS")) {
                    returnObj.put("status", "suc");
                    returnObj.put("sign", sign);
                    returnObj.put("nonce_str", nonce_str);
                    returnObj.put("mch_id", mch_id);
                    returnObj.put("appid", appid);
                    returnObj.put("prepay_id", prepay_id);
                    returnObj.put("code_url", code_url);
                    returnObj.put("out_trade_no", out_trade_no);
                } else {
                    String errMsg = "[ERROR]result_code:" + resHandler.getParameter("result_code") + " err_code:"
                            + resHandler.getParameter("err_code") + "err_code_des:"
                            + resHandler.getParameter("err_code_des");
                    // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                    returnObj.put("status", "ERROR-C");
                    returnObj.put("errMsg", errMsg);
                }
            } else {
                String errMsg = "return_code:" + return_code + "err_code:" + resHandler.getParameter("err_code")
                        + " return_msg:" + return_msg;
                // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                returnObj.put("status", "ERROR-B");
                returnObj.put("errMsg", errMsg);
            }
        } else {
            // 有可能因为网络原因,请求已经处理,但未收到应答。
            returnObj.put("status", "ERROR-A");
            returnObj.put("errMsg", httpClient.getResponseCode() + ":" + httpClient.getErrInfo());
        }
        // 获取debug信息,建议把请求、应答内容、debug信息,通信返回码写入日志,方便定位问题
        String detail = "http res:" + httpClient.getResponseCode() + "," + httpClient.getErrInfo() + ";" + "req url:"
                + requestUrl + ";" + ";" + "req debug:" + reqHandler.getDebugInfo() + ";" + "res content:" + rescontent
                + ";" + "res debug:" + resHandler.getDebugInfo() + ";";
        returnObj.put("detail", detail);
        return returnObj;
    }
    /**处理信息
     */
    public static JSONObject paymentData(JSONObject payObj,String key){
        JSONObject wxObj = new JSONObject();
        /**统一下单*/
        String payStatus = payObj.getString("status");
        if (payStatus.equals("suc")) {
            // JSONObject payObj = po.getJSONObject("inf");
            String appId = payObj.getString("appid");
            String nonceStr = payObj.getString("nonce_str");
            String prepay_id = payObj.getString("prepay_id");
            // JSAPI调用支付返回的数据
            String timeStamp = SimpleTool.getTenTime(new Date()).toString();
            String signType = "MD5";
            String packagef = "prepay_id=" + prepay_id;
            RequestHandler reqHandler = new RequestHandler(null, null);
            reqHandler.setParameter("appId", appId);
            reqHandler.setParameter("nonceStr", nonceStr);
            reqHandler.setParameter("timeStamp", timeStamp);
            reqHandler.setParameter("package", packagef);
            reqHandler.setParameter("signType", signType);
            reqHandler.setKey(key);
            String paySign = reqHandler.createSign();// 生成签名
            wxObj.put("orderNo", payObj.getString("out_trade_no"));
            wxObj.put("paySign", paySign);
            wxObj.put("appId", appId);
            wxObj.put("nonceStr", nonceStr);
            wxObj.put("package", packagef);
            wxObj.put("timeStamp", timeStamp);
        } else {
            throw new RuntimeException(payObj.toString());
        }
        return wxObj;
    }
    /**
     * 退款
     * @param appId 小程序/公众号 appId
     * @param partner 商户号
     * @param key 商户号秘钥
     * @param certPath 个人商户证书
     * @param out_trade_no 商户订单号
     * @param transaction_id 财付通订单号(微信订单号)
     * @param out_refund_no 商户退单号
     * @param total_fee 订单总额(单位:分)
     * @param refund_fee 退款金额(单位:分)
     * @return JSON status="SUCCESS"(成功) (状态,错误原因,该操作相关信息(参数,返回值))
     */
    public static JSONObject refund(String appId,String partner,String key,String certPath,String out_trade_no, String transaction_id, String out_refund_no, String total_fee,
            String refund_fee) {
         try{
             KeyStore keyStore = KeyStore.getInstance("PKCS12");
             FileInputStream instream = new FileInputStream(new File(certPath));
             try {
                 keyStore.load(instream,partner.toCharArray());
             }finally {
                 instream.close();
             }
             // Trust own CA and all self-signed certs
             SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,partner.toCharArray()).build();
             // Allow TLSv1 protocol only
             SSLConnectionSocketFactory sslsf;
            sslsf = new SSLConnectionSocketFactory(
                    sslcontext, new String[] { "TLSv1" }, null,
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                     .setSSLSocketFactory(sslsf).build();
             HttpPost httppost = new HttpPost(REFUND_URL);
             String xml = wxPayRefundData(appId, partner, key, out_trade_no, transaction_id, out_refund_no, total_fee, refund_fee);
             try {
                 StringEntity se = new StringEntity(xml);
                 httppost.setEntity(se);
                 CloseableHttpResponse responseEntry = httpclient.execute(httppost);
                 try {
                     HttpEntity entity = responseEntry.getEntity();
                     if (entity != null) {
                         SAXReader saxReader = new SAXReader();
                         Document document = saxReader.read(entity.getContent());
                         Element rootElt = document.getRootElement();
                         String returnCode = rootElt.elementText("return_code");
                         JSONObject result = new JSONObject();
                         if(returnCode.equals("SUCCESS")){
                             String resultCode = rootElt.elementText("result_code");
                             if(resultCode.equals("SUCCESS")) {
                                 result.put("weixinPayUrl", rootElt.elementText("code_url"));
                                 result.put("prepayId", rootElt.elementText("prepay_id"));
                                 result.put("msg", "success");
                                 String refund_id = rootElt.elementText("refund_id");//微信退款单号
                                 String r_out_refund_no = rootElt.elementText("out_refund_no");
                                 String errMsg = "商户号" + r_out_refund_no + "的退款流水号是:" + refund_id;
                                 result.put("status", "SUCCESS");
                                 result.put("errMsg", errMsg);
                                 result.put("refund_id", refund_id);
                             }else{
                                 String errMsg = "[ERROR]result_code:" + rootElt.elementText("result_code")+
                                         " err_code:" + rootElt.elementText("err_code");
                                 //错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                                 result.put("errMsg", errMsg);
                                 result.put("status","false");
                                 result.put("msg",rootElt.elementText("err_code_des"));
                             }
                         }else{
                             String errMsg = "[ERROR]return_code:" + rootElt.elementText("return_code");
                             //错误时,返回结果未签名,记录retcode、retmsg看失败详情。
                             result.put("errMsg", errMsg);
                             result.put("status","false");
                             result.put("msg",rootElt.elementText("return_msg"));
                         }
                         return result;
                     }
                     EntityUtils.consume(entity);
                 }
                 finally {
                     responseEntry.close();
                 }
             }
             finally {
                 httpclient.close();
             }
             return null;
         }catch(Exception e){
             e.printStackTrace();
             JSONObject result = new JSONObject();
             result.put("status","error");
             result.put("msg",e.getMessage());
             return result;
         }
    }
    /** 封装参数数据
     * @param appId 小程序/公众号 appId
     * @param partner 商户号
     * @param key 商户号秘钥
     * @param out_trade_no 商户订单号
     * @param transaction_id 财付通订单号(微信订单号)
     * @param out_refund_no 商户退单号
     * @param total_fee 订单总额(单位:分)
     * @param refund_fee 退款金额(单位:分)
     * @return
     */
    public static String wxPayRefundData(String appId,String partner,String key,String out_trade_no, String transaction_id,String out_refund_no,String total_fee,String refund_fee) {
        StringBuffer xml = new StringBuffer();
        String data = null;
        try {
            String nonceStr = SimpleTool.getUUIDName().substring(0,30);
            xml.append("</xml>");
            SortedMap<String,String> parameters = new TreeMap<String,String>();
            parameters.put("appid",appId);
            parameters.put("mch_id",partner);
            parameters.put("nonce_str", nonceStr);
            if(!StringUtils.isEmpty(out_trade_no)) {
                parameters.put("out_trade_no", out_trade_no);
            }
            if(!StringUtils.isEmpty(transaction_id)) {
                parameters.put("transaction_id", transaction_id);
            }
            parameters.put("out_refund_no", out_refund_no);
            parameters.put("fee_type", "CNY");
            parameters.put("total_fee", total_fee);//总金额
            parameters.put("refund_fee", refund_fee);//退款金额
            parameters.put("op_user_id",partner);
            parameters.put("sign", createSign(parameters,key));
            data =SortedMaptoXml(parameters);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            return null;
        }
        return data;
    }
    /**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     */
    public static String createSign(SortedMap<String, String> packageParams, String AppKey) {
        StringBuffer sb;
        sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + AppKey);
        String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
        return sign;
    }
    /**
     * @Author: HONGLINCHEN
     * @Description:请求值转换为xml格式 SortedMap转xml
     * @param params
     * @Date: 2017-9-7 17:18
     */
    private static String SortedMaptoXml(SortedMap<String,String> params) {
        StringBuilder sb = new StringBuilder();
        Set es = params.entrySet();
        Iterator it = es.iterator();
        sb.append("<xml>\n");
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            sb.append("<"+k+">");
            sb.append(v);
            sb.append("</"+k+">\n");
        }
        sb.append("</xml>");
        return sb.toString();
    }
}
hx_common/src/main/java/com/hx/mp/util/WXSignUtils.java
New file
@@ -0,0 +1,33 @@
package com.hx.mp.util;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
public class WXSignUtils {
    /**
     * 微信支付签名算法sign
     * @param characterEncoding
     * @param parameters
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static String createSign(String characterEncoding, SortedMap<Object,Object> parameters, String key){
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            if(null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + key);
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }
}
hx_common/src/main/java/com/hx/mp/util/WechatUtil.java
New file
@@ -0,0 +1,77 @@
package com.hx.mp.util;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import net.sf.json.JSONObject;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class WechatUtil {
    public static boolean initialized = false;
    //log4j日志
    private static Logger logger = LoggerFactory.getLogger(WechatUtil.class.getName());
    public static JSONObject encryptedData(String encryptedData, String session_key, String iv) throws Exception {
        JSONObject encrypted_obj = null;
         byte[] resultByte  =decrypt(Base64.decode(encryptedData),
                 Base64.decode(session_key),
                 Base64.decode(iv));
             if(null != resultByte && resultByte.length > 0){
                 String userInfo = new String(resultByte, "UTF-8");
                 encrypted_obj = JSONObject.fromObject(userInfo);
             }else{
                 logger.error("获取unionid解密失败:encryptedData="+encryptedData+";session_key="+session_key+";iv="+iv);
             }
        return encrypted_obj;
    }
    /**
     * AES解密
     * @param content 密文
     * @return
     * @throws InvalidAlgorithmParameterException
     * @throws NoSuchProviderException
     */
    public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws Exception {
        initialize();
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        Key sKeySpec = new SecretKeySpec(keyByte, "AES");
        cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
        byte[] result = cipher.doFinal(content);
        return result;
    }
    public static void initialize(){
        if (initialized) return;
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }
    //生成iv
    public static AlgorithmParameters generateIV(byte[] iv) throws Exception{
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }
}
hx_common/src/main/java/com/hx/mp/util/WxMpPayUtil.java
New file
@@ -0,0 +1,98 @@
package com.hx.mp.util;
import net.sf.json.JSONObject;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
/**
 * 微信小程序支付相关工具类
 */
public class WxMpPayUtil {
    /**小程序红包发送链接*/
    private static final String URL_SEND_RED_PACK = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendminiprogramhb";
    /**
     * 发送小程序红包
     * @param orderNo 订单号
     * @param mchId 商户号
     * @param mchKey 商户密钥
     * @param appId 小程序appId
     * @param sendName 发送者名称
     * @param openId 接收者openId
     * @param payFee 红包金额,以分为单位
     * @param wishing 祝福语
     * @param actName 活动名称
     * @param remark 备注
     * @param certPath 支付证书路径
     * @return
     */
    public static JSONObject sendMiniProgramReadPack(String orderNo, String mchId, String mchKey, String appId, String sendName, String openId,
                                                     int payFee, String wishing, String actName, String remark, String certPath)
    {
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("nonce_str", UUID.randomUUID().toString().substring(0, 30));
        parameters.put("mch_billno", orderNo);//商户订单号
        parameters.put("mchid", mchId);//商户号
        parameters.put("wxappid", appId);//公众账号appId
        parameters.put("send_name", sendName);//红包发送者名称
        parameters.put("re_openid", openId);//用户openId
        parameters.put("total_amount", payFee);//红包总金额,以分为单位
        parameters.put("total_num", 1);//红包数量,固定为1
        parameters.put("wishing", wishing);//红包祝福语,128字符
        parameters.put("act_name", actName);//活动名称
        parameters.put("remark", remark);//备注
        parameters.put("notify_way", "MINI_PROGRAM_JSAPI");//通知用户形式,固定
        String sign = WXSignUtils.createSign("UTF-8", parameters, mchKey);
        parameters.put("sign", sign);
        String xmlInfo = HttpXmlUtils.transferXml(parameters);
        JSONObject returnObj = new JSONObject();
        try {
            CloseableHttpResponse response = HttpUtil.Post(URL_SEND_RED_PACK, xmlInfo, true, certPath, mchId);
            String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
            Map<String, String> transferMap = HttpXmlUtils.parseRefundXml(transfersXml);
            boolean bl = false;
            if (transferMap.size() > 0) {
                if (transferMap.get("return_code").equals("SUCCESS")) {
                    // 通讯成功
                    if (transferMap.get("result_code").equals("SUCCESS")) {
                        // 成功需要进行的逻辑操作
                        returnObj.put("status", "suc");
                    } else {
                        bl = true;
                        returnObj.put("status", "fail");
                        returnObj.put("errMsg", transferMap.get("err_code") + "|" + transferMap.get("err_code_des"));
                    }
                } else {
                    bl = true;
                    // 通讯不成功
                    returnObj.put("status", "fail");
                    returnObj.put("errMsg", transferMap.get("return_msg"));
                }
            } else {
                bl = true;
                returnObj.put("status", "fail");
                returnObj.put("errMsg", "返回为空");
            }
            if (bl) {
                System.out.println("企业付款失败:" + transfersXml);
            }
        } catch (Exception e) {
            e.printStackTrace();
            returnObj.put("status", "fail");
            returnObj.put("errMsg", e.getMessage());
        }
        return returnObj;
    }
}
hx_common/src/main/java/com/hx/mp/util/XMLUtil.java
New file
@@ -0,0 +1,109 @@
package com.hx.mp.util;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
 * xml������
 *JX
 *linhan
 */
public class XMLUtil {
    /**
     * ����xml,���ص�һ��Ԫ�ؼ�ֵ�ԡ�����һ��Ԫ�����ӽڵ㣬��˽ڵ��ֵ���ӽڵ��xml��ݡ�
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static Map doXMLParse(String strxml) throws JDOMException, IOException {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        if(null == strxml || "".equals(strxml)) {
            return null;
        }
        Map m = new HashMap();
        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while(it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if(children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = XMLUtil.getChildrenText(children);
            }
            m.put(k, v);
        }
        //�ر���
        in.close();
        return m;
    }
    /**
     * ��ȡ�ӽ���xml
     * @param children
     * @return String
     */
    @SuppressWarnings("rawtypes")
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if(!children.isEmpty()) {
            Iterator it = children.iterator();
            while(it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if(!list.isEmpty()) {
                    sb.append(XMLUtil.getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        return sb.toString();
    }
    /**
     * ��ȡxml�����ַ�
     * @param strxml
     * @return
     * @throws IOException
     * @throws JDOMException
     */
    public static String getXMLEncoding(String strxml) throws JDOMException, IOException {
        InputStream in = HttpClientUtil.String2Inputstream(strxml);
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        in.close();
        return (String)doc.getProperty("encoding");
    }
}
hx_common/src/main/java/com/hx/mybatis/aes/handler/GenericStringHandler.java
New file
@@ -0,0 +1,72 @@
package com.hx.mybatis.aes.handler;
import com.hx.mybatis.aes.springbean.VariableAesKey;
import com.hx.util.mysql.aes.MysqlHexAesTool;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
 * @author CJH
 * @Date 2021-01-02
 * // @MappedTypes注解中的类代表此转换器可以自动转换为的java对象,@MappedJdbcTypes注解中设置的是对应的jdbctype,mysql的json对象对应的jdbctype为VARCHAR。
 */
@MappedTypes(value = {String.class})
@MappedJdbcTypes(value = {JdbcType.VARCHAR}, includeNullJdbcType = true)
public class GenericStringHandler extends BaseTypeHandler<String> {
    public GenericStringHandler() {
    }
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
    }
    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String data = rs.getString(columnName);
        if(data != null && data.length()%32==0 && MysqlHexAesTool.isHexStrValid(data)){
            try{
                data = MysqlHexAesTool.decryptData(data, VariableAesKey.getAesKey(columnName),null);
            }catch (Exception e){
                //e.printStackTrace();
            }
        }
        return data;
    }
    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String data = rs.getString(columnIndex);
        if(data != null && data.length()%32==0 && MysqlHexAesTool.isHexStrValid(data)){
            try{
                data = MysqlHexAesTool.decryptData(data, VariableAesKey.getAesKey(null),null);
            }catch (Exception e){
                //e.printStackTrace();
            }
        }
        return data;
    }
    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String data = cs.getString(columnIndex);
        if(data != null && data.length() < 129 && data.length()%32==0 && MysqlHexAesTool.isHexStrValid(data)){
            try{
                data = MysqlHexAesTool.decryptData(data, VariableAesKey.getAesKey(null),null);
            }catch (Exception e){
                //e.printStackTrace();
            }
        }
        return data;
    }
}
hx_common/src/main/java/com/hx/mybatis/aes/springbean/ConstantBean.java
New file
@@ -0,0 +1,46 @@
package com.hx.mybatis.aes.springbean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 * 通用常量集中营
 * @author CJH
 */
@Component
public class ConstantBean {
    /**获取AES秘钥的配置(从什么包获取到)*/
    @Value("${mysql.hxe.aes.find.packs:}")
    private String packPath;
    /**固定AES的秘钥*/
    @Value("${mysql.hxe.aes.fixd.key:}")
    private String fixedAesKey;
    /**数据库初始化加密字段版本号*/
    @Value("${mysql.hxe.aes.init.version:}")
    private String initVersion;
    public String getPackPath() {
        return packPath;
    }
    public void setPackPath(String packPath) {
        this.packPath = packPath;
    }
    public String getFixedAesKey() {
        return fixedAesKey;
    }
    public void setFixedAesKey(String fixedAesKey) {
        this.fixedAesKey = fixedAesKey;
    }
    public String getInitVersion() {
        return initVersion;
    }
    public void setInitVersion(String initVersion) {
        this.initVersion = initVersion;
    }
}
hx_common/src/main/java/com/hx/mybatis/aes/springbean/ExportTableAliasVisitor.java
New file
@@ -0,0 +1,53 @@
package com.hx.mybatis.aes.springbean;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
import java.util.HashMap;
import java.util.Map;
/**
 * ExportTableAliasVisitor
 * @author Mwg
 * @date 2020/09/08 23:47
 */
public class ExportTableAliasVisitor extends SQLASTVisitorAdapter {
    private Map<String,String> tableMap = new HashMap<>();
    public Map<String, String> getTableMap() {
        return tableMap;
    }
    public void setTableMap(Map<String, String> tableMap) {
        this.tableMap = tableMap;
    }
    @Override
    public boolean visit(SQLExprTableSource x) {
        //别名,如果有别名,别名保持不变
        //System.out.println("alias:"+x.getAlias());//别名
        //System.out.println("expr:"+x.getExpr());//表名
        tableMap.put(x.getExpr().toString(),x.getAlias());
        //String s = StringUtils.isEmpty(x.getAlias()) ? x.getExpr().toString() : x.getAlias();
        // 修改表名,不包含点才加 select id from c left join d on c.id = d.id 中的c 和 d
        /*if(!x.getExpr().toString().contains(".")) {
            x.setExpr("`" + dbName.get() + "`." + x.getExpr());
        }*/
        //x.setExpr("mymymytable");//修改表名
        //x.setAlias("aa");//修改别名
        //x.setAlias(s);
        return true;
    }
}
hx_common/src/main/java/com/hx/mybatis/aes/springbean/FieldData.java
New file
@@ -0,0 +1,40 @@
package com.hx.mybatis.aes.springbean;
import java.util.Set;
public class FieldData {
    //主键
    private String id;
    //数据库表明
    private String tableName;
    //需要加密得表字段
    private Set<String> encrypFields;
    public FieldData() {
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getTableName() {
        return tableName;
    }
    public void setTableName(String tableName) {
        this.tableName = tableName;
    }
    public Set<String> getEncrypFields() {
        return encrypFields;
    }
    public void setEncrypFields(Set<String> encrypFields) {
        this.encrypFields = encrypFields;
    }
}
hx_common/src/main/java/com/hx/mybatis/aes/springbean/InitMysqlData.java
New file
@@ -0,0 +1,197 @@
package com.hx.mybatis.aes.springbean;
import com.gitee.sunchenbin.mybatis.actable.annotation.Column;
import com.gitee.sunchenbin.mybatis.actable.annotation.Table;
import com.hx.common.annotations.MysqlHexAes;
import com.hx.common.dao.mapper.CommonMapper;
import com.hx.common.service.CommonService;
import com.hx.exception.ServiceException;
import com.hx.mybatisTool.SqlSentence;
import com.hx.util.StringUtils;
import com.hx.util.mysql.aes.MysqlHexAesTool;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InitMysqlData {
    /**
     * 项目启动就执行后就执行该方法
     */
    //@PostConstruct 2022-06-17屏掉,暂时用不上
    public static void initData(String packPath, CommonService commonService){
        //项目启动的时候填入
        if(!StringUtils.isEmpty(packPath)){
            Set<Class<?>> classes = VariableAesKey.classData(packPath);
            SqlSentence sqlSentence = new SqlSentence();
            Map<String,Object> values = new HashMap<>();
            //解析表数据
            List<FieldData> fieldDatas = entityhandle(classes);
            int pageSize = 500;
            //创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(20);
            try{
                for(FieldData fieldData:fieldDatas){
                    //获取条数
                    sqlSentence.sqlSentence("SELECT COUNT(0) FROM "+fieldData.getTableName(),values);
                    int total = commonService.selectCountSql(sqlSentence);
                    if(total ==0 ){
                        continue;
                    }
                    int pageTotal = total/pageSize+1;
                    for(int i= 0;i<pageTotal;i++){
                        int finalI = i;
                        fixedThreadPool.execute(new Runnable() {
                            @Override
                            public void run() {
                                //更新数据
                                updateData(fieldData,commonService, finalI,pageSize);
                            }
                        });
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                fixedThreadPool.shutdown();
            }
        }
    }
    /**更新数据*/
    public static void updateData(FieldData fieldData,CommonService commonService,int pageNum,int pageSize){
        SqlSentence sqlSentence = new SqlSentence();
        Map<String,Object> values = new HashMap<>();
        //查询数据
        StringBuilder selectField = new StringBuilder();
        selectField.append(fieldData.getId());
        for(String fieldName:fieldData.getEncrypFields()){
            selectField.append(","+fieldName);
        }
        pageNum = pageNum*pageSize;
        sqlSentence.sqlSentence("SELECT "+selectField.toString()+" FROM "+fieldData.getTableName()+" LIMIT "+pageNum+","+pageSize,values);
        List<Map<String,Object>> list = commonService.selectListMap(CommonMapper.class,sqlSentence);
        boolean isUpdate = false;
        for (Map<String,Object> map:list){
            isUpdate = false;
            StringBuilder setField = new StringBuilder();
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String mapKey = entry.getKey();
                String mapValue = (String) entry.getValue();
                if(StringUtils.isEmpty(mapValue)){
                    continue;
                }
                if(mapValue.length()%32==0 && MysqlHexAesTool.isHexStrValid(mapValue)){
                    continue;
                }
                if(fieldData.getId().equals(mapKey)){
                    continue;
                }
                if(setField.length()>0){
                    setField.append(",");
                }
                setField.append(mapKey+" = #{m."+mapKey+"}");
                isUpdate = true;
            }
            if(isUpdate){
                values = map;
                sqlSentence.sqlSentence("UPDATE "+fieldData.getTableName()+" SET "+setField.toString()+" WHERE "+fieldData.getId()+" = #{m."+fieldData.getId()+"}",values);
                if(commonService.updateSentence(sqlSentence)!=1){
                    throw new ServiceException("更新超过1条,更新失败!");
                }
            }
        }
    }
    /**获取到表的数据*/
    public static List<FieldData> entityhandle(Set<Class<?>> classes){
        List<FieldData> fildDatas = new ArrayList<>();
        //存储单表字段信息
        FieldData fildData;
        //存储需要加密的字段
        Set<String> encrypFields;
        String fildName;
        for(Class<?> cl:classes){
            fildData = new FieldData();
            encrypFields = new HashSet<>();
            //表名称
            if(!cl.isAnnotationPresent(Table.class)){
                continue;
            }
            Table table = cl.getAnnotation(Table.class);
            fildData.setTableName(table.name());
            // 取得本类的全部属性
            Field[] fields = cl.getDeclaredFields();
            fields = VariableAesKey.getPatentFields(fields,cl);
            for (Field field:fields) {
                fildName = null;
                if(field.isAnnotationPresent(Column.class)){
                    Column column = field.getAnnotation(Column.class);
                    fildName = column.name();
                    if(StringUtils.isEmpty(fildName)){
                        fildName = field.getName();
                    }
                    if(column.isKey()){
                        fildData.setId(fildName);
                    }
                }else{
                    fildName = field.getName();
                }
                // 判断方法中是否有指定注解类型的注解
                if (!field.isAnnotationPresent(MysqlHexAes.class)) {
                    continue;
                }
                // 根据注解类型返回方法的指定类型注解
                MysqlHexAes mysqlHexAes = field.getAnnotation(MysqlHexAes.class);
                //判断版本号是不是一样的
                if(!StringUtils.isEmpty(VariableAesKey.INIT_VERSION)){
                    if(!VariableAesKey.INIT_VERSION.equals(mysqlHexAes.initVersion())){
                        continue;
                    }
                }else{
                    if(!StringUtils.isEmpty(mysqlHexAes.initVersion())){
                        continue;
                    }
                }
                String aesKey = mysqlHexAes.aesKey();
                if(StringUtils.isEmpty(aesKey)){
                    aesKey = VariableAesKey.AES_KEY;
                    if(StringUtils.isEmpty(aesKey)){
                        throw new RuntimeException("mysql的AES秘钥不能为空:"+field.getName());
                    }
                }
                encrypFields.add(fildName);
            }
            //是否有需要加密得字段
            if(encrypFields.size()<=0){
                continue;
            }
            fildData.setEncrypFields(encrypFields);
            fildDatas.add(fildData);
        }
        return fildDatas;
    }
}
hx_common/src/main/java/com/hx/mybatis/aes/springbean/MySqlInterceptor.java
New file
@@ -0,0 +1,101 @@
package com.hx.mybatis.aes.springbean;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.List;
import java.util.Properties;
@Component
@Intercepts({
        @Signature(
                type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class
        })
})
public class MySqlInterceptor implements Interceptor {
    private static Logger logger = LoggerFactory.getLogger(MySqlInterceptor.class.getName());
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 方法一
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
        //先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler,然后就到BaseStatementHandler的成员变量mappedStatement
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        //id为执行的mapper方法的全路径名,如com.uv.dao.UserMapper.insertUser
        //String id = mappedStatement.getId();
        //sql语句类型 select、delete、insert、update
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        BoundSql boundSql = statementHandler.getBoundSql();
        // 获取节点的配置
        Configuration configuration = mappedStatement.getConfiguration();
        // 获取参数
        Object parameterObject = boundSql.getParameterObject();
        // MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作
        // MetaObject metaObject1 = configuration.newMetaObject(parameterObject);
        //获取sql中问号的基本信息
        List<ParameterMapping> parameterMappings = boundSql
                .getParameterMappings();
        /*for (ParameterMapping parameterMapping : parameterMappings) {
            String propertyName = parameterMapping.getProperty();
            System.out.println("propertyName:"+ propertyName);
            System.out.println("parameterObject:"+ parameterObject);
        }*/
        //这里可以进行sql修改
        //获取到原始sql语句
        String sql = boundSql.getSql();
        //新增
        if(sqlCommandType == SqlCommandType.INSERT){
            sql = SqlUtils.insertSql(sql, VariableAesKey.aesKeysTable);
        }else if(sqlCommandType == SqlCommandType.UPDATE){
            sql = SqlUtils.updateSql(sql, VariableAesKey.aesKeysTable);
        }else if(sqlCommandType == SqlCommandType.SELECT){
            if(VariableAesKey.isRun == 1){
                sql = SqlUtils.selectSql(sql, VariableAesKey.aesKeysTable);
            }
        }else if(sqlCommandType == SqlCommandType.DELETE){
            sql = SqlUtils.deleteSql(sql, VariableAesKey.aesKeysTable);
        }
        //通过反射修改sql语句
        Field field = boundSql.getClass().getDeclaredField("sql");
        field.setAccessible(true);
        field.set(boundSql, sql);
        return invocation.proceed();
    }
    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }
    @Override
    public void setProperties(Properties properties) {
    }
}
hx_common/src/main/java/com/hx/mybatis/aes/springbean/SqlUtils.java
New file
@@ -0,0 +1,578 @@
package com.hx.mybatis.aes.springbean;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.util.JdbcUtils;
import com.hx.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
 * sql语句处理工具
 * @author CJH 2022-01-12
 */
public class SqlUtils {
    //log4j日志
    private static Logger logger = LoggerFactory.getLogger(SqlUtils.class.getName());
    /**查询加密数据处理,只对查询做处理
     * @param sql sql语句
     * @param aesKeysTable aes秘钥
     * @return
     */
    public static String selectSql(String sql,Map<String,Map<String,String>> aesKeysTable){
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLSelectStatement sqlStatement = (SQLSelectStatement) parser.parseSelect();
        SQLSelect sqlSelect = sqlStatement.getSelect();
        if (sqlSelect.getQuery() instanceof SQLSelectQueryBlock) {
            // 非union的查询语句
            return selectSqlRoutine( sqlStatement,aesKeysTable);
        } else if (sqlSelect.getQuery() instanceof SQLUnionQuery) {
            // union的查询语句
            return selectSqlUnion( sql, sqlStatement, aesKeysTable);
        }else {
            return selectSqlRoutine( sqlStatement,aesKeysTable);
        }
    }
    /**查询加密数据处理,只对查询做处理,select返回不做处理(Union特殊语句)
     * @param sql sql语句
     * @param aesKeysTable aes秘钥
     * @return
     */
    public static String selectSqlUnion(String sql,SQLSelectStatement sqlStatement,Map<String,Map<String,String>> aesKeysTable){
        //获取表和别名
        ExportTableAliasVisitor visitorTable = new ExportTableAliasVisitor();
        sqlStatement.accept(visitorTable);
        Map<String,String> tableMaps = visitorTable.getTableMap();
        //获取所有的字段
        MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
        sqlStatement.accept(visitor);
        //遍历所有字段
        Collection<TableStat.Column> columns= visitor.getColumns();
        //处理需要加密得字段
        if(!StringUtils.isEmpty(sql)){
            Map<String,String> aesKeys = null;
            String aeskey = null;
            //把剩下的拼接上来
            String tableAl = null;
            for(TableStat.Column column:columns){
                aesKeys= aesKeysTable.get(column.getTable());
                if(aesKeys == null){
                    continue;
                }
                aeskey = aesKeys.getOrDefault(column.getName(),null);
                if(StringUtils.isEmpty(aeskey)){
                    continue;
                }
                tableAl = tableMaps.get(column.getTable());
                if(!StringUtils.isEmpty(tableAl)){
                    tableAl = tableAl+"."+column.getName();
                }else{
                    tableAl = column.getName();
                }
                sql = sql.replaceAll("((?<!\\.)\\b"+tableAl+"\\b(?!\\.))","AES_DECRYPT(UNHEX("+tableAl+"),'"+aeskey+"')");
            }
        }
        return sql;
    }
    /**查询加密数据处理,只对查询做处理,select返回不做处理(常规语句)
     * @param sqlStatement sql语句
     * @param aesKeysTable aes秘钥
     * @return
     */
    public static String selectSqlRoutine(SQLSelectStatement sqlStatement,Map<String,Map<String,String>> aesKeysTable){
        //解析select查询
        //SQLSelect sqlSelect = sqlStatement.getSelect()
        //获取sql查询块
        SQLSelectQueryBlock sqlSelectQuery = null;
        boolean b = true;
        try{
            sqlSelectQuery = (SQLSelectQueryBlock)sqlStatement.getSelect().getQuery() ;
        }catch (Exception e){
            b = false;
            logger.error("解析sql报错:"+e.getMessage());
        }
        if(!b){
            return "err";
        }
        StringBuffer out = new StringBuffer() ;
        //创建sql解析的标准化输出
        SQLASTOutputVisitor sqlastOutputVisitor = SQLUtils.createFormatOutputVisitor(out , null , JdbcUtils.MYSQL) ;
        //获取表和别名
        ExportTableAliasVisitor visitorTable = new ExportTableAliasVisitor();
        sqlStatement.accept(visitorTable);
        Map<String,String> tableMaps = visitorTable.getTableMap();
        //获取所有的字段
        MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
        sqlStatement.accept(visitor);
        //遍历所有字段
        Collection<TableStat.Column> columns= visitor.getColumns();
        StringBuilder sqlWhere = new StringBuilder();
        StringBuilder sqlSelect = new StringBuilder();
        String expr = null;
        sqlSelect.append("SELECT ");
        //解析select返回的数据字段项
        for (SQLSelectItem sqlSelectItem : sqlSelectQuery.getSelectList()) {
            if(sqlSelect.length() > 7){
                sqlSelect.append(",");
            }
            out.delete(0, out.length()) ;
            sqlSelectItem.accept(sqlastOutputVisitor) ;
            expr = out.toString();
            sqlSelect.append(expr);
           /* if(expr.indexOf("SELECT") == -1){
                sqlSelect.append(expr);
            }else{
                //sqlSelect.append("(");
                sqlSelect.append(expr);
                //sqlSelect.append(")");
               *//* if(!StringUtils.isEmpty(sqlSelectItem.getAlias())){
                    sqlSelect.append(" AS "+sqlSelectItem.getAlias());
                }*//*
            }*/
        }
        //解析from
        if(sqlSelectQuery.getFrom() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getFrom().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" FROM "+out);
        }
        //解析where
        if(sqlSelectQuery.getWhere() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getWhere().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" WHERE "+out+" ");
        }
        if(sqlSelectQuery.getGroupBy() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getGroupBy().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" "+out);
        }
        if(sqlSelectQuery.getOrderBy() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getOrderBy().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" "+out);
        }
        if(sqlSelectQuery.getLimit() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getLimit().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" "+out);
        }
        //处理where需要加密得字段
        String sql = sqlWhere.toString();
        if(!StringUtils.isEmpty(sql)){
            Map<String,String> aesKeys = null;
            String aeskey = null;
            //把剩下的拼接上来
            String tableAl = null;
            for(TableStat.Column column:columns){
                aesKeys= aesKeysTable.get(column.getTable());
                if(aesKeys == null){
                    continue;
                }
                aeskey = aesKeys.getOrDefault(column.getName(),null);
                if(StringUtils.isEmpty(aeskey)){
                    continue;
                }
                tableAl = tableMaps.get(column.getTable());
                if(!StringUtils.isEmpty(tableAl)){
                    tableAl = tableAl+"."+column.getName();
                }else{
                    tableAl = column.getName();
                }
                sql = sql.replaceAll("((?<!\\.)\\b"+tableAl+"\\b(?!\\.))","AES_DECRYPT(UNHEX("+tableAl+"),'"+aeskey+"')");
            }
        }
        return sqlSelect.toString()+sql;
    }
    /**
     * 处理select返回字段的参数
     * @param sql
     * @param aesKeysTable
     * @param tableMaps
     * @param columns
     * @return
     */
    public static String selectSqlHandle(String sql,Map<String,Map<String,String>> aesKeysTable
            ,Map<String,String> tableMaps,Collection<TableStat.Column> columns){
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLSelectStatement sqlStatement = (SQLSelectStatement) parser.parseSelect();
        //获取格式化的slq语句
        sql = sqlStatement.toString();
        //解析select查询
        //SQLSelect sqlSelect = sqlStatement.getSelect() ;
        //获取sql查询块
        SQLSelectQueryBlock sqlSelectQuery = (SQLSelectQueryBlock)sqlStatement.getSelect().getQuery() ;
        StringBuffer out = new StringBuffer() ;
        //创建sql解析的标准化输出
        SQLASTOutputVisitor sqlastOutputVisitor = SQLUtils.createFormatOutputVisitor(out , null , JdbcUtils.MYSQL) ;
        StringBuilder sqlWhere = new StringBuilder();
        StringBuilder sqlSelect = new StringBuilder();
        String expr = null;
        sqlSelect.append("SELECT ");
        //解析select返回的数据字段项
        for (SQLSelectItem sqlSelectItem : sqlSelectQuery.getSelectList()) {
            if(sqlSelect.length() > 7){
                sqlSelect.append(",");
            }
            expr = sqlSelectItem.getExpr().toString();
            if(expr.indexOf("SELECT") == -1){
                sqlSelect.append(expr);
                if(!StringUtils.isEmpty(sqlSelectItem.getAlias())){
                    sqlSelect.append(" AS "+sqlSelectItem.getAlias());
                }
            }else{
                sqlSelect.append("(");
                selectSqlHandle(expr,aesKeysTable,tableMaps,columns);
                sqlSelect.append(")");
                if(!StringUtils.isEmpty(sqlSelectItem.getAlias())){
                    sqlSelect.append(" AS "+sqlSelectItem.getAlias());
                }
            }
        }
        //解析from
        if(sqlSelectQuery.getFrom() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getFrom().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" FROM "+out);
        }
        //解析where
        if(sqlSelectQuery.getWhere() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getWhere().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" WHERE "+out+" ");
        }
        if(sqlSelectQuery.getGroupBy() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getGroupBy().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" "+out);
        }
        if(sqlSelectQuery.getOrderBy() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getOrderBy().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" "+out);
        }
        if(sqlSelectQuery.getLimit() != null){
            out.delete(0, out.length()) ;
            sqlSelectQuery.getLimit().accept(sqlastOutputVisitor) ;
            sqlWhere.append(" "+out);
        }
        sql = sqlWhere.toString();
        if(!StringUtils.isEmpty(sql)){
            Map<String,String> aesKeys = null;
            String aeskey = null;
            //把剩下的拼接上来
            String tableAl = null;
            for(TableStat.Column column:columns){
                aesKeys= aesKeysTable.get(column.getTable());
                if(aesKeys == null){
                    continue;
                }
                aeskey = aesKeys.getOrDefault(column.getName(),null);
                if(StringUtils.isEmpty(aeskey)){
                    continue;
                }
                tableAl = tableMaps.get(column.getTable());
                if(!StringUtils.isEmpty(tableAl)){
                    tableAl = tableAl+"."+column.getName();
                }else{
                    tableAl = column.getName();
                }
                sql = sql.replaceAll("((?<!\\.)\\b"+tableAl+"\\b(?!\\.))","AES_DECRYPT(UNHEX("+tableAl+"),'"+aeskey+"')");
            }
        }
        return sqlSelect.toString()+sql;
    }
    /**新增加密数据处理
     * @param sql sql语句
     * @param aesKeysTable aes秘钥
     * @return
     */
    public static String insertSql(String sql,Map<String,Map<String,String>> aesKeysTable){
        //装载重写的sql语句
        StringBuilder splicingSql = new StringBuilder();
        sql = SQLUtils.format(sql, JdbcConstants.MYSQL);
        String[] datas = sql.split("VALUES",2);
        splicingSql.append(datas[0]+"VALUES ");
        //重新拼接SQL语句
        //解析sql语句
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement statement = parser.parseStatement();
        MySqlInsertStatement insert = (MySqlInsertStatement)statement;
        String insertName = insert.getTableName().getSimpleName();
        //根据表名称获取到AES秘钥
        Map<String,String> aesKeys= aesKeysTable.get(insertName);
        if(aesKeys == null){
            return sql;
        }
        //获取所有的字段
        List<SQLExpr> columns = insert.getColumns();
        String fildValue = null;
        String aeskey = null;
        //遍历值
        List<SQLInsertStatement.ValuesClause> vcl = insert.getValuesList();
        for(int j = 0; j<vcl.size(); j++){
            if( j != 0){
                splicingSql.append(",");
            }
            for(int i = 0;i < columns.size();i++){
                //查询改字段是否需要加密
                aeskey = aesKeys.getOrDefault(columns.get(i).toString(),null);
                fildValue = vcl.get(j).getValues().get(i).toString();
                if(i == 0){
                    splicingSql.append("(");
                    if(aeskey != null && fildValue.indexOf("AES_ENCRYPT") == -1){
                        splicingSql.append("HEX(AES_ENCRYPT("+fildValue+",'"+aeskey+"'))");
                    }else{
                        splicingSql.append(fildValue);
                    }
                }else if(i == columns.size()-1){
                    splicingSql.append(",");
                    if(aeskey != null && fildValue.indexOf("AES_ENCRYPT") == -1){
                        splicingSql.append("HEX(AES_ENCRYPT("+fildValue+",'"+aeskey+"'))");
                    }else{
                        splicingSql.append(fildValue);
                    }
                    splicingSql.append(")");
                }else{
                    splicingSql.append(",");
                    if(aeskey != null && fildValue.indexOf("AES_ENCRYPT") == -1){
                        splicingSql.append("HEX(AES_ENCRYPT("+fildValue+",'"+aeskey+"'))");
                    }else{
                        splicingSql.append(fildValue);
                    }
                }
            }
        }
        return splicingSql.toString();
    }
    /**更新加密数据处理
     * @param sql sql语句
     * @param aesKeysTable aes秘钥
     * @return
     */
    public static String updateSql(String sql,Map<String,Map<String,String>> aesKeysTable){
        //装载重写的sql语句
        StringBuilder splicingSql = new StringBuilder();
        //sql = SQLUtils.format(sql, JdbcConstants.MYSQL);
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement sqlStatement = parser.parseStatement();
        //获取格式化的slq语句
        sql = sqlStatement.toString();
        MySqlUpdateStatement updateStatement = (MySqlUpdateStatement)sqlStatement;
        String insertName = updateStatement.getTableName().getSimpleName();
        String[] datas = sql.split("WHERE",2);
        Map<String,String> aesKeys = aesKeysTable.get(insertName);
        if(aesKeys == null){
            return sql;
        }
        splicingSql.append("UPDATE "+insertName+" SET ");
        String aeskey = null;
        String fildValue = null;
        List<SQLUpdateSetItem> items = updateStatement.getItems();
        for(int i = 0;i<items.size();i++){
            if(i != 0){
                splicingSql.append(",");
            }
            SQLUpdateSetItem item = items.get(i);
            //查询改字段是否需要加密
            aeskey = aesKeys.getOrDefault(item.getColumn().toString(),null);
            fildValue = item.getValue().toString();
            if(aeskey != null && fildValue.indexOf("AES_ENCRYPT") == -1){
                splicingSql.append(item.getColumn()+" = HEX(AES_ENCRYPT("+fildValue+",'"+aeskey+"'))");
            }else{
                splicingSql.append(item.getColumn()+" = "+fildValue);
            }
        }
        String sqlWhere = " WHERE";
        //把剩下的拼接上来
        if(datas.length > 1){
            for(int i =1;i<datas.length;i++){
                sqlWhere = sqlWhere+datas[i];
            }
            parser = new MySqlStatementParser("SELECT * FROM "+insertName+" "+sqlWhere);
            sqlStatement = parser.parseStatement();
            ExportTableAliasVisitor visitorTable = new ExportTableAliasVisitor();
            sqlStatement.accept(visitorTable);
            //获取表和别名
            Map<String,String> tableMaps = visitorTable.getTableMap();
            tableMaps.put(insertName,null);
            //获取所有的字段
            MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
            sqlStatement.accept(visitor);
            String tableAl = null;
            //遍历所有字段
            Collection<TableStat.Column> columns= visitor.getColumns();
            for(TableStat.Column column:columns){
                aesKeys= aesKeysTable.get(column.getTable());
                if(aesKeys == null){
                    continue;
                }
                aeskey = aesKeys.getOrDefault(column.getName(),null);
                if(StringUtils.isEmpty(aeskey)){
                    continue;
                }
                tableAl = tableMaps.get(column.getTable());
                if(!StringUtils.isEmpty(tableAl)){
                    tableAl = tableAl+"."+column.getName();
                }else{
                    tableAl = column.getName();
                }
                sqlWhere = sqlWhere.replaceAll("((?<!\\.)\\b"+tableAl+"\\b(?!\\.))","AES_DECRYPT(UNHEX("+tableAl+"),'"+aeskey+"')");
            }
        }
        splicingSql.append(sqlWhere);
        return splicingSql.toString();
    }
    /**删除加密数据处理
     * @param sql sql语句
     * @param aesKeysTable aes秘钥
     * @return
     */
    public static String deleteSql(String sql,Map<String,Map<String,String>> aesKeysTable){
        //装载重写的sql语句
        StringBuilder splicingSql = new StringBuilder();
        //sql = SQLUtils.format(sql, JdbcConstants.MYSQL);
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement sqlStatement = parser.parseStatement();
        //获取格式化的slq语句
        sql = sqlStatement.toString();
        MySqlDeleteStatement deleteStatement = (MySqlDeleteStatement)sqlStatement;
        String insertName = deleteStatement.getTableName().getSimpleName();
        String[] datas = sql.split("WHERE",2);
        Map<String,String> aesKeys = aesKeysTable.get(insertName);
        if(aesKeys == null){
            return sql;
        }
        splicingSql.append("DELETE FROM "+insertName);
        String aeskey = null;
        String sqlWhere = " WHERE";
        //把剩下的拼接上来
        if(datas.length > 1){
            for(int i =1;i<datas.length;i++){
                sqlWhere = sqlWhere+datas[i];
            }
            parser = new MySqlStatementParser("SELECT * FROM "+insertName+" "+sqlWhere);
            sqlStatement = parser.parseStatement();
            ExportTableAliasVisitor visitorTable = new ExportTableAliasVisitor();
            sqlStatement.accept(visitorTable);
            //获取表和别名
            Map<String,String> tableMaps = visitorTable.getTableMap();
            tableMaps.put(insertName,null);
            //获取所有的字段
            MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
            sqlStatement.accept(visitor);
            String tableAl = null;
            //遍历所有字段
            Collection<TableStat.Column> columns= visitor.getColumns();
            for(TableStat.Column column:columns){
                aesKeys= aesKeysTable.get(column.getTable());
                if(aesKeys == null){
                    continue;
                }
                aeskey = aesKeys.getOrDefault(column.getName(),null);
                if(StringUtils.isEmpty(aeskey)){
                    continue;
                }
                tableAl = tableMaps.get(column.getTable());
                if(!StringUtils.isEmpty(tableAl)){
                    tableAl = tableAl+"."+column.getName();
                }else{
                    tableAl = column.getName();
                }
                sqlWhere = sqlWhere.replaceAll("((?<!\\.)\\b"+tableAl+"\\b(?!\\.))","AES_DECRYPT(UNHEX("+tableAl+"),'"+aeskey+"')");
            }
        }
        splicingSql.append(sqlWhere);
        return splicingSql.toString();
    }
}
hx_common/src/main/java/com/hx/mybatis/aes/springbean/VariableAesKey.java
New file
@@ -0,0 +1,294 @@
package com.hx.mybatis.aes.springbean;
import com.gitee.sunchenbin.mybatis.actable.annotation.Table;
import com.hx.common.annotations.MysqlHexAes;
import com.hx.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
 * 获取指定包里面的AES秘钥
 */
@Component
public class VariableAesKey {
    //log4j日志
    private static Logger logger = LoggerFactory.getLogger(VariableAesKey.class.getName());
    @Resource
    private ConstantBean constantBean;
    /**是否已经启动完*/
    public static int isRun = 0;
    /**存储所有AES的秘钥*/
    public static Map<String,String> aesKeys = new HashMap<>();
    /**根据表明来存储AES秘钥*/
    public static Map<String,Map<String,String>> aesKeysTable = new HashMap<>();
    /**固定的aes秘钥*/
    public static String AES_KEY = null;
    /**数据库加密字段初始化版本号*/
    public static String INIT_VERSION = null;
    /**存储AES秘钥*/
    public static void setAesKey(String aesKeyFild,String aesKey){
        aesKeys.put(aesKeyFild,aesKey);
    }
    /**获取AES秘钥*/
    public static String getAesKey(String aesKeyFild){
        if(aesKeyFild == null){
            return AES_KEY;
        }
        if(StringUtils.isEmpty(aesKeys.get(aesKeyFild))){
            return AES_KEY;
        }else {
            return  aesKeys.get(aesKeyFild);
        }
    }
    /**
     * 项目启动就执行后就执行该方法
     */
    @PostConstruct
    public void VariableAesKey(){
        System.out.println("加载AES");
        isRun = 1;
        //项目启动的时候填入
        logger.info("扫描获取AES的包:" + constantBean.getPackPath());
        AES_KEY = constantBean.getFixedAesKey();
        INIT_VERSION = constantBean.getInitVersion();
        if(!StringUtils.isEmpty(constantBean.getPackPath())){
            Set<Class<?>> classes = classData(constantBean.getPackPath());
            logger.info("扫描获取AES的包classes:" + classes.size());
            Map<String,String> aesKeysFild = new HashMap<>();
            boolean isAes = false;
            String tableName = null;
            for(Class<?> cl:classes){
                //表名称
                boolean hasAnnotation = cl.isAnnotationPresent(Table.class);
                if(!hasAnnotation){
                    continue;
                }
                Table table = cl.getAnnotation(Table.class);
                tableName = table.name();
                aesKeysFild = new HashMap<>();
                isAes = false;
                // 取得本类的全部属性
                Field[] fields = cl.getDeclaredFields();
                fields = getPatentFields(fields,cl);
                for (Field field:fields) {
                    // 判断方法中是否有指定注解类型的注解
                    hasAnnotation = field.isAnnotationPresent(MysqlHexAes.class);
                    if (hasAnnotation) {
                        // 根据注解类型返回方法的指定类型注解
                        MysqlHexAes mysqlHexAes = field.getAnnotation(MysqlHexAes.class);
                        //String aesKeyField = mysqlHexAes.aesKeyField();
                        String aesKey = mysqlHexAes.aesKey();
                        if(StringUtils.isEmpty(aesKey)){
                            aesKey = constantBean.getFixedAesKey();
                            if(StringUtils.isEmpty(aesKey)){
                                throw new RuntimeException("mysql的AES秘钥不能为空:"+field.getName());
                            }
                        }
                        String key = aesKeys.get(field.getName());
                        if(StringUtils.isEmpty(key)){
                            aesKeys.put(field.getName(),aesKey);
                            aesKeysFild.put(field.getName(),aesKey);
                            isAes = true;
                        }else{
                            isAes = true;
                            aesKeysFild.put(field.getName(),aesKey);
                            if(!aesKey.equals(key)){
                                throw new RuntimeException("字段/定义的AES秘钥字段【"+field.getName()+"】多个一样,但是AES秘钥不一样");
                            }
                        }
                    }
                }
                if(isAes){
                    aesKeysTable.put(tableName,aesKeysFild);
                }
            }
        }
    }
    /**获取包下面的所有文件*/
    public static Set<Class<?>> classData(String packPath){
        Set<Class<?>> classes = new LinkedHashSet();
        String[] split = packPath.split(",|;");
        String[] var3 = split;
        int var4 = split.length;
        label82:
        for(int var5 = 0; var5 < var4; ++var5) {
            String pack = var3[var5];
            boolean recursive = true;
            String packageName = pack;
            String packageDirName = pack.replace('.', '/');
            try {
                Enumeration dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
                while(true) {
                    label75:
                    while(true) {
                        if (!dirs.hasMoreElements()) {
                            continue label82;
                        }
                        URL url = (URL)dirs.nextElement();
                        String protocol = url.getProtocol();
                        if ("file".equals(protocol)) {
                            System.err.println("file类型的扫描:" + pack);
                            String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                            findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
                        } else if ("jar".equals(protocol)) {
                            System.err.println("jar类型的扫描");
                            try {
                                JarFile jar = ((JarURLConnection)url.openConnection()).getJarFile();
                                Enumeration entries = jar.entries();
                                while(true) {
                                    JarEntry entry;
                                    String name;
                                    int idx;
                                    do {
                                        do {
                                            if (!entries.hasMoreElements()) {
                                                continue label75;
                                            }
                                            entry = (JarEntry)entries.nextElement();
                                            name = entry.getName();
                                            if (name.charAt(0) == '/') {
                                                name = name.substring(1);
                                            }
                                        } while(!name.startsWith(packageDirName));
                                        idx = name.lastIndexOf(47);
                                        if (idx != -1) {
                                            packageName = name.substring(0, idx).replace('/', '.');
                                        }
                                    } while(idx == -1 && !recursive);
                                    if (name.endsWith(".class") && !entry.isDirectory()) {
                                        String className = name.substring(packageName.length() + 1, name.length() - 6);
                                        try {
                                            classes.add(Class.forName(packageName + '.' + className));
                                        } catch (ClassNotFoundException var20) {
                                            var20.printStackTrace();
                                        }
                                    }
                                }
                            } catch (IOException var21) {
                                var21.printStackTrace();
                            }
                        }
                    }
                }
            } catch (IOException var22) {
                var22.printStackTrace();
            }
        }
        return classes;
    }
    /**
     * 以文件的形式来获取包下的所有Class
     *
     * @param packageName
     * @param packagePath
     * @param recursive
     * @param classes
     */
    public static void findAndAddClassesInPackageByFile(
            String packageName,
            String packagePath,
            final boolean recursive,
            Set<Class<?>> classes){
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter(){
            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
            @Override
            public boolean accept(File file){
                return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
            }
        });
        // 循环所有文件
        for (File file : dirfiles){
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
            }else{
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0, file.getName().length() - 6);
                try{
                    // 添加到集合中去
                    // classes.add(Class.forName(packageName + '.' +
                    // className));
                    // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                }catch (ClassNotFoundException e){
                    // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 获取父类的字段
     * @param fields
     * @param clas
     * @return
     */
    public static Field[] getPatentFields(Field[] fields,Class<?> clas){
        if (clas.getSuperclass() != null) {
            Class clsSup = clas.getSuperclass();
            List<Field> fieldList = new ArrayList<Field>();
            fieldList.addAll(Arrays.asList(fields));
            fieldList.addAll(Arrays.asList(clsSup.getDeclaredFields()));
            fields = new Field[fieldList.size()];
            int i = 0;
            for (Object field : fieldList.toArray()) {
                fields[i] = (Field) field;
                i++;
            }
            fields = getPatentFields(fields,clsSup);
        }
        return  fields;
    }
}
hx_common/src/main/java/com/hx/mybatis/date/handler/GenericDateHandler.java
New file
@@ -0,0 +1,38 @@
package com.hx.mybatis.date.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.*;
import java.time.LocalDateTime;
/**
 * @author CJH
 * @Date 2021-01-02
 * // @MappedTypes注解中的类代表此转换器可以自动转换为的java对象,@MappedJdbcTypes注解中设置的是对应的jdbctype,mysql的json对象对应的jdbctype为VARCHAR。
 */
@MappedTypes(value = {LocalDateTime.class})
@MappedJdbcTypes(value = {JdbcType.TIMESTAMP}, includeNullJdbcType = true)
public class GenericDateHandler extends BaseTypeHandler<Timestamp> {
    public GenericDateHandler() {
    }
    public void setNonNullParameter(PreparedStatement ps, int i, Timestamp parameter, JdbcType jdbcType) throws SQLException {
        ps.setTimestamp(i, parameter);
    }
    public Timestamp getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getTimestamp(columnName);
    }
    public Timestamp getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getTimestamp(columnIndex);
    }
    public Timestamp getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getTimestamp(columnIndex);
    }
}
hx_common/src/main/java/com/hx/mybatisTool/SqlSentence.java
New file
@@ -0,0 +1,251 @@
package com.hx.mybatisTool;
import com.hx.exception.TipsException;
import com.hx.util.SimpleTool;
import com.hx.util.StringUtils;
import java.util.Map;
/**
 * mybatis 自定义处理sql语句
 * @author chenjiahe
 * @Data: 2020-06-08
 */
public class SqlSentence {
    /**执行语句*/
    private String sqlSentence;
    /**新增存在查询判断*/
    private String whereExist;
    private Map<String,Object> m;
    /**排序*/
    private String orderBy;
    /**开始页数*/
    private Integer startPage = 0;
    /**每页数量*/
    private Integer pageNum = 0;
    /**条数(当前类使用)*/
    private Integer pageSize;
    //////////////////////////////////////////////////////////////
    /********************mother****************************/
    public SqlSentence()
    {
    }
    public SqlSentence(Class c, String where, Map<String, Object> values)
    {
        if(StringUtils.isEmpty(where))
        {
            throw new TipsException("sql is null");
        }
        if(values == null)
        {
            throw new TipsException("values is null");
        }
        sqlSentence = "select * from " + c.getSimpleName()+ " where " + where;
        m = values;
    }
    public SqlSentence(String where, Map<String, Object> values)
    {
        if(StringUtils.isEmpty(where))
        {
            throw new TipsException("sql is null");
        }
        if(values == null)
        {
            throw new TipsException("values is null");
        }
        sqlSentence = where;
        m = values;
    }
    /**
     * sql整条语句
     * @param sql 如:select * from user Where name = #{m.userName} order by age desc
     * @param values 存放的值如:values.put("userName","ChenJiaHe")
     */
    public void sqlSentence(String sql,Map<String,Object> values) {
        if(StringUtils.isEmpty(sql))
        {
            throw new TipsException("sql is null");
        }
        if(values == null)
        {
            throw new TipsException("values is null");
        }
        sqlSentence = sql;
        m = values;
    }
    /**
     * sql整条语句-分页
     * @param sql 如:select * from user Where name = #{m.userName} order by age desc
     * @param values 存放的值如:values.put("userName","ChenJiaHe")
     * @param pageNum 当前页数
     * @param pageSize 当前条数
     */
    public void sqlSentencePage(String sql,Map<String,Object> values,int pageNum,int pageSize) {
        if(StringUtils.isEmpty(sql)) {
            throw new TipsException("sql is null");
        }
        if(values == null) {
            throw new TipsException("values is null");
        }
        if(pageNum < 1){
            pageNum = 1;
        }
        if(pageSize < 1){
            pageSize = 1;
        }
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        //算起点
        int pageStart = (pageNum-1)*pageSize;
        sql = sql+" LIMIT "+pageStart+","+pageSize;
        sqlSentence = sql;
        m = values;
    }
    /**分页组装信息
     * @param data 装载信息
     * @param totalNum 总页数
     * @return 装载信息
     */
    public Map<String,Object> pageAssembleData(Map<String,Object> data,int totalNum){
        data.put("pageNum",pageNum);
        data.put("pageSize",pageSize);
        data.put("total",totalNum);
        int pages;
        if(pageSize > 0){
            if(totalNum%pageSize > 0){
                pages = totalNum/pageSize+1;
            }else{
                pages = totalNum/pageSize;
            }
        }else{
            pages = 0;
        }
        data.put("pages",pages);
        if(pages <= pageNum){
            data.put("isLastPage",true);
        }else{
            data.put("isLastPage",false);
        }
        return data;
    }
    /**
     * 查询的语句
     * @param sql 如:id = #{m.userId} order by age DESC
     * @param values 存放的值如:values.put("userId","123456")
     */
    public void sqlWhere(String sql,Map<String,Object> values) {
        if(!SimpleTool.checkNotNull(values)){
            throw new TipsException("values is null");
        }
        if(!SimpleTool.checkNotNull(sql)) {
            sql = "1=1";
        }
        sqlSentence = sql;
        m = values;
    }
    /**
     * 更新语句的语句
     * @param sql 如:name = #{m.name},age = ? WHERE id = #{m.id}
     * @param values 存放的值
     */
    public void sqlUpdate(String sql,Map<String,Object> values) {
        if(!SimpleTool.checkNotNull(values)){
            throw new TipsException("values is null");
        }
        m = values;
        sqlSentence = sql;
    }
    /************************************************************************/
    public Map<String, Object> getM() {
        return m;
    }
    public void setM(Map<String, Object> m) {
        this.m = m;
    }
    public String getSqlSentence() {
        return sqlSentence;
    }
    public void setSqlSentence(String sqlSentence) {
        this.sqlSentence = sqlSentence;
    }
    public String getOrderBy() {
        return orderBy;
    }
    public void setOrderBy(String orderBy) {
        this.orderBy = orderBy;
    }
    public Integer getStartPage() {
        return startPage;
    }
    public void setStartPage(Integer startPage) {
        this.startPage = startPage;
    }
    public Integer getPageNum() {
        return pageNum;
    }
    public void setPageNum(Integer pageNum) {
        this.pageNum = pageNum;
    }
    public Integer getStartIndex()
    {
        return (startPage - 1) * pageNum;
    }
    public String getWhereExist() {
        return whereExist;
    }
    public void setWhereExist(String whereExist) {
        if(StringUtils.isNull(whereExist)){
            whereExist = null;
        }
        this.whereExist = whereExist;
    }
    public Integer getPageSize() {
        return pageSize;
    }
    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }
}
hx_common/src/main/java/com/hx/mybatisTool/SqlStringTool.java
New file
@@ -0,0 +1,172 @@
package com.hx.mybatisTool;
import com.hx.util.StringUtils;
import java.util.List;
import java.util.Map;
/**
 * Sql工具类
 * @author fwq
 */
public class SqlStringTool {
    /**基础key*/
    private static final String BASE_KEY = "k";
    /**AND符号*/
    private static final String AND_STR = " AND ";
    /**左边括号拼接*/
    private static final String LEFT_STR = "#{m.";
    /**右边括号拼接*/
    private static final String RIGHT_STR = "}";
    /**逗号分隔*/
    private static final String SIGN_STR = ",";
    /**IN左符号*/
    private static final String IN_LEFT = " IN ( ";
    /**IN右符号*/
    private static final String IN_RIGHT = " ) ";
    /**
     * 递归key,直到不重复,这个递归是针对同一个sqlMap,防止同方法多个查询时存在key覆盖问题。
     * PS:建议查询完上一次,清理sqlMap后再传递进来,减少递归的操作
     */
    private static String getKey(String key, Map<String, Object> sqlMap) {
        if (sqlMap.get(key) != null) {
            getKey(BASE_KEY + key, sqlMap);
        }
        return key;
    }
    /**
     * 拼接sql语句
     * @param sql         StringBuilder的sql语句
     * @param tableColumn 含别名表字段,例如:user AS u 根据id查询时传递u.id
     * @param dataList    要循环的数值,List集合
     * @param sqlMap      sql语句对应的参数Map
     */
    public static void handleList(StringBuilder sql, String tableColumn, List<String> dataList, Map<String, Object> sqlMap) {
        if (sql == null || StringUtils.isEmpty(tableColumn) || dataList == null || dataList.size() < 1) {
            return;
        }
        String key = null;
        sql.append(AND_STR).append(tableColumn).append(IN_LEFT);
        for (int i = 0; i < dataList.size(); i++) {
            key = getKey(BASE_KEY + i, sqlMap);
            sql.append(LEFT_STR).append(key).append(RIGHT_STR).append(SIGN_STR);
            sqlMap.put(key, dataList.get(i));
        }
        sql.deleteCharAt(sql.length() - 1).append(IN_RIGHT);
    }
    /**
     * 拼接sql语句
     * @param sql         StringBuffer的sql语句
     * @param tableColumn 含别名表字段,例如:user AS u 根据id查询时传递u.id
     * @param dataList    要循环的数值,List集合
     * @param sqlMap      sql语句对应的参数Map
     */
    public static void handleList(StringBuffer sql, String tableColumn, List<String> dataList, Map<String, Object> sqlMap) {
        if (sql == null || StringUtils.isEmpty(tableColumn) || dataList == null || dataList.size() < 1) {
            return;
        }
        String key = null;
        sql.append(AND_STR).append(tableColumn).append(IN_LEFT);
        for (int i = 0; i < dataList.size(); i++) {
            key = getKey(BASE_KEY + i, sqlMap);
            sql.append(LEFT_STR).append(key).append(RIGHT_STR).append(SIGN_STR);
            sqlMap.put(key, dataList.get(i));
        }
        sql.deleteCharAt(sql.length() - 1).append(IN_RIGHT);
    }
    /**
     * 拼接sql语句
     * @param sql         StringBuilder的sql语句
     * @param tableColumn 含别名表字段,例如:user AS u 根据id查询时传递u.id
     * @param dataList    要循环的数值,String数组
     * @param sqlMap      sql语句对应的参数Map
     */
    public static void handleList(StringBuilder sql, String tableColumn, String[] dataList, Map<String, Object> sqlMap) {
        if (sql == null || StringUtils.isEmpty(tableColumn) || dataList == null || dataList.length < 1) {
            return;
        }
        String key = null;
        sql.append(AND_STR).append(tableColumn).append(IN_LEFT);
        for (int i = 0; i < dataList.length; i++) {
            key = getKey(BASE_KEY + i, sqlMap);
            sql.append(LEFT_STR).append(key).append(RIGHT_STR).append(SIGN_STR);
            sqlMap.put(key, dataList[i]);
        }
        sql.deleteCharAt(sql.length() - 1).append(IN_RIGHT);
    }
    /**
     * 拼接sql语句
     * @param sql         StringBuffer的sql语句
     * @param tableColumn 含别名表字段,例如:user AS u 根据id查询时传递u.id
     * @param dataList    要循环的数值,String数组
     * @param sqlMap      sql语句对应的参数Map
     */
    public static void handleList(StringBuffer sql, String tableColumn, String[] dataList, Map<String, Object> sqlMap) {
        if (sql == null || StringUtils.isEmpty(tableColumn) || dataList == null || dataList.length < 1) {
            return;
        }
        String key = null;
        sql.append(AND_STR).append(tableColumn).append(IN_LEFT);
        for (int i = 0; i < dataList.length; i++) {
            key = getKey(BASE_KEY + i, sqlMap);
            sql.append(LEFT_STR).append(key).append(RIGHT_STR).append(SIGN_STR);
            sqlMap.put(key, dataList[i]);
        }
        sql.deleteCharAt(sql.length() - 1).append(IN_RIGHT);
    }
    /**
     * 拼接sql语句
     * @param sql         StringBuilder的sql语句
     * @param tableColumn 含别名表字段,例如:user AS u 根据id查询时传递u.id
     * @param dataList    要循环的数值,Map数组对象
     * @param dataListKey Map数组对象中要循环值对应的key
     * @param sqlMap      sql语句对应的参数Map
     */
    public static void handleList(StringBuilder sql, String tableColumn, List<Map<String, Object>> dataList, String dataListKey, Map<String, Object> sqlMap) {
        if (sql == null || StringUtils.isEmpty(tableColumn) || dataList == null || dataList.size() < 1) {
            return;
        }
        String key = null;
        sql.append(AND_STR).append(tableColumn).append(IN_LEFT);
        for (int i = 0; i < dataList.size(); i++) {
            key = getKey(BASE_KEY + i, sqlMap);
            sql.append(LEFT_STR).append(key).append(RIGHT_STR).append(SIGN_STR);
            sqlMap.put(key, dataList.get(i).get(dataListKey));
        }
        sql.deleteCharAt(sql.length() - 1).append(IN_RIGHT);
    }
    /**
     * 拼接sql语句
     * @param sql         StringBuffer的sql语句
     * @param tableColumn 含别名表字段,例如:user AS u 根据id查询时传递u.id
     * @param dataList    要循环的数值,Map数组对象
     * @param dataListKey Map数组对象中要循环值对应的key
     * @param sqlMap      sql语句对应的参数Map
     */
    public static void handleList(StringBuffer sql, String tableColumn, List<Map<String, Object>> dataList, String dataListKey, Map<String, Object> sqlMap) {
        if (sql == null || StringUtils.isEmpty(tableColumn) || dataList == null || dataList.size() < 1) {
            return;
        }
        String key = null;
        sql.append(AND_STR).append(tableColumn).append(IN_LEFT);
        for (int i = 0; i < dataList.size(); i++) {
            key = getKey(BASE_KEY + i, sqlMap);
            sql.append(LEFT_STR).append(key).append(RIGHT_STR).append(SIGN_STR);
            sqlMap.put(key, dataList.get(i).get(dataListKey));
        }
        sql.deleteCharAt(sql.length() - 1).append(IN_RIGHT);
    }
}
hx_common/src/main/java/com/hx/platform/tool/PlatformSign.java
hx_common/src/main/java/com/hx/redis/RedisConfig.java
New file
@@ -0,0 +1,34 @@
package com.hx.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
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.StringRedisSerializer;
@Configuration
@EnableCaching
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}
hx_common/src/main/java/com/hx/redis/RedisUtil.java
New file
@@ -0,0 +1,414 @@
package com.hx.redis;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
 * 文件处理工具
 *
 * @author wangrenhuang
 * @Date 2021-10-19
 */
@Component
public class RedisUtil {
    /**
     * [redis]
     */
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 切换数据库
     * @param dataNumber 数据库编号
     */
    public void setDataBase(int dataNumber) {
        LettuceConnectionFactory connectionFactory = (LettuceConnectionFactory) redisTemplate.getConnectionFactory();
        if (connectionFactory != null && dataNumber != connectionFactory.getDatabase()) {
            connectionFactory.setDatabase(dataNumber);
            this.redisTemplate.setConnectionFactory(connectionFactory);
            connectionFactory.resetConnection();
        }
    }
    /**
     * [判断key是否存在]
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            return false;
        }
    }
    /**
     * [普通缓存获取]
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
    /**
     * [普通缓存删除]
     *
     * @param key 键
     * @return 值
     */
    public boolean delete(String key) {
        try {
            Boolean aBoolean = redisTemplate.hasKey(key);
            return aBoolean == false ? true : redisTemplate.delete(key);
        } catch (Exception e) {
            return false;
        }
    }
    /**
     * [普通缓存放入]
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 26
     * 指定缓存失效时间
     * 27
     *
     * @param key  键
     *             28
     * @param time 时间(秒)
     *             29
     * @return 30
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 设置到期时间
     * @param key       对应键
     * @param time      时长
     * @param timeUnit  时间单位
     * @return
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        try {
            if (time > 0) {
                return redisTemplate.expire(key, time, timeUnit);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }
    /**
     * hash 删除操作
     *
     * @param key   键
     * @param valueKey 值
     * @return true成功 false 失败
     */
    public boolean hashDel(String key, Object... valueKey) {
        try {
            redisTemplate.opsForHash().delete(key,valueKey);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * hash 设置hashMapt操作
     *
     * @param key   键
     * @return true成功 false 失败
     */
    public boolean hashSetMap(String key, Map<String,Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * hash 设置单个hashMap操作
     *
     * @param key   键
     * @return true成功 false 失败
     */
    public boolean hashSet(String hashKey, String key, Object value) {
        try {
            redisTemplate.opsForHash().put(hashKey,key,value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * hash 获取整个hashKey数据
     *
     * @param hashKey   键
     * @return true成功 false 失败
     */
    public Map<Object, Object> hashGetAll(String hashKey) {
        try {
            return redisTemplate.opsForHash().entries(hashKey);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * hash 获取单个hashKey
     *
     * @param hashKey   键
     * @return true成功 false 失败
     */
    public Object hashGet(String hashKey,Object key) {
        try {
            return redisTemplate.opsForHash().get(hashKey,key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 新增-左插入
     *
     * @param listKey   键
     * @return true成功 false 失败
     */
    public Object leftPush(String listKey,Object value) {
        try {
            return redisTemplate.opsForList().leftPush(listKey,value);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 新增-左插入(存在才插入)
     *
     * @param listKey   键
     * @return true成功 false 失败
     */
    public Object leftPushIfPresent(String listKey,Object value) {
        try {
            return redisTemplate.opsForList().leftPushIfPresent(listKey,value);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 新增-右插入(存在才插入)
     *
     * @param listKey   键
     * @return true成功 false 失败
     */
    public Object rightPushIfPresent(String listKey,Object value) {
        try {
            return redisTemplate.opsForList().rightPushIfPresent(listKey,value);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 新增-右插入
     *
     * @param listKey   键
     * @return true成功 false 失败
     */
    public Object rightPush(String listKey,Object value) {
        try {
            return redisTemplate.opsForList().rightPush(listKey,value);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 弹出-左
     *
     * @param listKey   键
     * @return true成功 false 失败
     */
    public Object leftPop(String listKey) {
        try {
            return redisTemplate.opsForList().leftPop(listKey);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 弹出-右
     *
     * @param listKey   键
     * @return true成功 false 失败
     */
    public Object rightPop(String listKey) {
        try {
            return redisTemplate.opsForList().rightPop(listKey);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 获取索引下的值
     *
     * @param key   键
     * @param index 索引
     * @return true成功 false 失败
     */
    public Object listGet(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key,index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 获取索引下的值
     *
     * @param key   键
     * @param start 开始位置 0是开始位置
     * @param end 结束位置,-1返回所有
     * @return true成功 false 失败
     */
    public List<Object> listGetRange(String key, long start , long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 获取长度
     *
     * @param listKey   键
     * @return true成功 false 失败
     */
    public Object listSize(String listKey) {
        try {
            return redisTemplate.opsForList().size(listKey);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * list 删除
     *
     * @param listKey   键
     * @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素; index<0, 从尾部开始删除第一个值等于value的元素
     * @param value 删除的值
     * @return true成功 false 失败
     */
    public Object listRemove(String listKey,long index,Object value) {
        try {
            return redisTemplate.opsForList().remove(listKey, index, value);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * @param key     键
     * @param value   值
     * @param timeOut 时间
     * @param unit    时间单位
     */
    public Boolean setIfAbsent(String key, Object value, long timeOut, TimeUnit unit) {
        try {
            return redisTemplate.opsForValue().setIfAbsent(key, value, timeOut, unit);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
hx_common/src/main/java/com/hx/repeat/check/RequestRepeatUtil.java
New file
@@ -0,0 +1,76 @@
package com.hx.repeat.check;
import com.hx.common.annotations.repeat.RequestRepeat;
import com.hx.exception.TipsException;
import com.hx.redis.RedisUtil;
import com.hx.util.DateUtil;
import com.hx.util.IPUtils;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
 * URL防重复提交
 * @author CJH
 */
public class RequestRepeatUtil {
    /**请求重复校验
     * 目前区分重复是IP地址和请求方法,如果想要更精准,传code
     * @param code 前缀标识,用于区分不同请求来源,长度最好12位之内,可空
     * @param request HttpServletRequest
     * @param redisUtil redis
     * @param millisecond 间隔时间,毫秒(默认500毫秒)
     * @param annotateCheck 是否注解校验,如果是,将以注解来做校验,否则就全部做校验
     * @param method 请求方法,方法或者类上面有校验注解,注解跳过或者拦截
     */
    public static void checkRequest(String code,HttpServletRequest request, RedisUtil redisUtil, Long millisecond
            , boolean annotateCheck, Method method){
        //优先校验注解,优先方法再到类
        RequestRepeat requestRepeat =  method.getAnnotation(RequestRepeat.class);
        if(requestRepeat != null){
            if(requestRepeat.isRepeat()){
                check(code,request,redisUtil,requestRepeat.millisecond());
            }else{
                return;
            }
        }else{
            requestRepeat = method.getClass().getAnnotation(RequestRepeat.class);
            if(requestRepeat != null){
                if(requestRepeat.isRepeat()){
                    check(code,request,redisUtil,requestRepeat.millisecond());
                }else{
                    return;
                }
            }
        }
        //通过注解校验,不需要全部
        if(!annotateCheck){
            check(code,request,redisUtil,millisecond);
        }
    }
    public static void check(String code,HttpServletRequest request,RedisUtil redisUtil,Long millisecond){
        //没有设置,默认0.5秒
        if(millisecond == null){
            millisecond = 500L;
        }
        //获取请求的IP地址
        String ip = IPUtils.getIpAddr(request);
        //获取URL
        String method = request.getServletPath();
        if(code != null){
            code = code+"-"+ip+"-"+method;
        }else{
            code = ip+"-"+method;
        }
        if(!redisUtil.setIfAbsent(code, DateUtil.formatDate(new Date(),"yyyy-MM-dd HH:mm:ss"),millisecond, TimeUnit.MILLISECONDS)){
            throw new TipsException("请勿频繁操作!");
        }
    }
}
hx_common/src/main/java/com/hx/resultTool/ResponseCode.java
New file
@@ -0,0 +1,30 @@
package com.hx.resultTool;
/**
 * 统一状态码
 * @author chenjiahe
 * @Data: 2020-06-20
 */
public final class ResponseCode {
    /*成功*/
    public static final String SUCCESS = "100";
    /*错误提示,前端根据这个码弹出提示*/
    public static final String ERROR_TIPS="200";
    /*参数验证错误*/
    public static final String ERROR_PARAMS_VALIDATOR="205";
    /*业务验证错误*/
    public static final String ERROR_SERVICE_VALIDATOR="300";
    /*系统数据错误*/
    public static final String ERROR_DATA_VALIDATOR="400";
    /*登录有误*/
    public static final String ERROR_LOGIN="603";
    /*系统异常*/
    public static final String ERROR_SYSTEM = "999";
    /*签名错误*/
    public static final String ERROR_SIGN = "203";
}
hx_common/src/main/java/com/hx/resultTool/Result.java
New file
@@ -0,0 +1,125 @@
package com.hx.resultTool;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hx.exception.TipsException;
import java.io.Serializable;
import java.util.List;
/**
 * 统一返回格式
 * @author chenjiahe
 * @Data: 2020-06-20
 */
public class Result implements Serializable {
    private static final long serialVersionUID = -3948389268046368059L;
    private String code;
    private String msg;
    private Object data;
    public Result() {}
    public Result(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public static Result success() {
        Result Result = new Result();
        Result.setCode(ResponseCode.SUCCESS);
        Result.setMsg("SUCCESS");
        return Result;
    }
    public static Result success(Object data) {
        Result Result = new Result();
        Result.setCode(ResponseCode.SUCCESS);
        Result.setData(data);
        Result.setMsg("SUCCESS");
        return Result;
    }
    public static Result failure(String code, String msg) {
        Result Result = new Result();
        Result.setCode(code);
        Result.setMsg(msg);
        return Result;
    }
    public static Result failure(String code, String msg, Object data) {
        Result Result = new Result();
        Result.setCode(code);
        Result.setMsg(msg);
        Result.setData(data);
        return Result;
    }
    /**校验返回码*/
    public Boolean checkCode(){
        if(ResponseCode.SUCCESS.equals(code)){
            return true;
        }
        return false;
    }
    /**校验返回码,进行错误提示*/
    public void checkTips(){
        if(!ResponseCode.SUCCESS.equals(code)){
            throw new TipsException("请求失败:"+this.code+","+this.msg);
        }
    }
    /**返回数据转JSONObject*/
    public JSONObject getJsonObject(Object data){
        return JSONObject.parseObject(JSON.toJSONString(data));
    }
    /**返回数据转JSONArray*/
    public JSONArray getJsonArray(Object data){
        return JSONArray.parseArray(JSON.toJSONString(data));
    }
    /**返回数据转对象*/
    public <T> T getObject(Object data, Class<T> clazz) {
        return JSONObject.parseObject(JSON.toJSONString(data), clazz);
    }
    /**返回数据转列表*/
    public <T> List<T> getArray(Object data, Class<T> clazz) {
        return JSONArray.parseArray(JSON.toJSONString(data), clazz);
    }
    /*******************************************************************************/
    public String getCode() {
        return this.code;
    }
    public void setCode(final String code) {
        this.code = code;
    }
    public String getMsg() {
        return this.msg;
    }
    public void setMsg(final String msg) {
        this.msg = msg;
    }
    public Object getData() {
        return this.data;
    }
    public void setData(final Object data) {
        this.data = data;
    }
}
hx_common/src/main/java/com/hx/security/request/RequestRestriction.java
New file
@@ -0,0 +1,39 @@
package com.hx.security.request;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**设置限制请求*/
@Configuration
public class RequestRestriction {
    @Bean
    public ConfigurableServletWebServerFactory configurableServletWebServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.addContextCustomizers(context -> {
            SecurityConstraint securityConstraint = new SecurityConstraint();
            securityConstraint.setUserConstraint("CONFIDENTIAL");
            SecurityCollection collection = new SecurityCollection();
            //设置不安全请求不能通过
            collection.addPattern("/*");
            collection.addMethod("HEAD");
            collection.addMethod("PUT");
            collection.addMethod("DELETE");
            collection.addMethod("OPTIONS");
            collection.addMethod("TRACE");
            collection.addMethod("COPY");
            collection.addMethod("SEARCH");
            collection.addMethod("PROPFIND");
            //collection.addMethod("PATCH");
            securityConstraint.addCollection(collection);
            context.addConstraint(securityConstraint);
        });
        return factory;
    }
}
hx_common/src/main/java/com/hx/util/Aes.java
New file
@@ -0,0 +1,113 @@
package com.hx.util;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
/**
 * AES加密工具类
 */
public class Aes {
    /**
     * 将二进制转换成16进制
     *
     * @param buf 字节数组
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }
    /**
     * 将16进制转换为二进制
     *
     * @param hexStr 16进制字符
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
    /**
     * 加密
     * @param str 待加密字符串
     * @param secret 密钥
     * @return
     */
    public static byte[] encrypt(String str, String secret) {
        if (null != str) {
            byte[] bytes = null;
            try {
                Base64 base64 = new Base64();
                String ALGORITHM = "AES";
                SecretKey desKey = new SecretKeySpec(secret.getBytes("UTF-8"), ALGORITHM);// 生成密钥
                Cipher c;
                c = Cipher.getInstance(ALGORITHM);
                c.init(Cipher.ENCRYPT_MODE, desKey);
                bytes = c.doFinal(str.getBytes("UTF-8"));
                return bytes;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * 解密
     * @param str 待解密字符串
     * @param secret 密钥
     * @return
     */
    public static byte[] decrypt(byte[] str, String secret) {
        try {
            String ALGORITHM = "AES";
            SecretKey desKey = new SecretKeySpec(secret.getBytes("UTF-8"), ALGORITHM);// 生成密钥
            Cipher c = Cipher.getInstance(ALGORITHM);
            c.init(Cipher.DECRYPT_MODE, desKey);
            return c.doFinal(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) throws UnsupportedEncodingException {
        String content = "apiKey=phitabfaceapi&userId=o5W1it6Pvqn6vPX6E1BGERH8J1lw";
        String password = "phitabfacesecret";
        byte[] encode = encrypt(content, password);
        String code = parseByte2HexStr(encode);
        System.out.println("密文字符串:" + code);
        //16进制字符串转成字节数组
        byte[] decode = parseHexStr2Byte(code);
        // 解密
        byte[] decryptResult = decrypt(decode, password);
        System.out.println("解密后:" + new String(decryptResult, "UTF-8")); //不转码会乱码
    }
}
hx_common/src/main/java/com/hx/util/AesUtil.java
New file
@@ -0,0 +1,125 @@
package com.hx.util;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
 * AES加解密工具
 * 使用该类,需要行替换local_policy.jar及us_export_policy.jar
 * @author ChenJiaHe
 *
 */
public class AesUtil {
    /**16位加密秘钥*/
    public static final String SECRET = "huoXiong16816888";
    /**
     * AES加密
     *
     * @param str
     *            需要加密的明文
     * @param secret
     *            秘钥
     * @return 加密后的密文(base64编码字符串)
     */
    public static String aesEncryp(String str, String secret) {
        if (null != str) {
            byte[] bytes = null;
            try {
                Base64 base64 = new Base64();
                String ALGORITHM = "AES";
                SecretKey deskey = new SecretKeySpec(secret.getBytes("UTF-8"), ALGORITHM);// 生成密钥
                Cipher c;
                c = Cipher.getInstance(ALGORITHM);
                c.init(Cipher.ENCRYPT_MODE, deskey);
                bytes = c.doFinal(str.getBytes("UTF-8"));
                if (bytes != null) {
                    return new String(base64.encode(bytes));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * AES解密
     *
     * @param str
     *            需要解密的秘文
     * @param secret
     *            秘钥
     * @return 解密后的明文
     */
    public static String aesDecryp(String str, String secret) {
        try {
            Base64 base64 = new Base64();
            String ALGORITHM = "AES";
            SecretKey deskey = new SecretKeySpec(secret.getBytes("UTF-8"), ALGORITHM);// 生成密钥
            Cipher c = Cipher.getInstance(ALGORITHM);
            c.init(Cipher.DECRYPT_MODE, deskey);
            return new String(c.doFinal(base64.decode(str.getBytes("UTF-8"))), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * AES加密(固定秘钥)
     *
     * @param str 需要加密的明文
     * @return 加密后的密文(base64编码字符串)
     */
    public static String aesEncryp(String str) {
        String secret = SECRET;
        if (null != str) {
            byte[] bytes = null;
            try {
                Base64 base64 = new Base64();
                String ALGORITHM = "AES";
                SecretKey deskey = new SecretKeySpec(secret.getBytes("UTF-8"), ALGORITHM);// 生成密钥
                Cipher c;
                c = Cipher.getInstance(ALGORITHM);
                c.init(Cipher.ENCRYPT_MODE, deskey);
                bytes = c.doFinal(str.getBytes("UTF-8"));
                if (bytes != null) {
                    return new String(base64.encode(bytes));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * AES解密(固定秘钥)
     *
     * @param str 需要解密的秘文
     * @return 解密后的明文
     */
    public static String aesDecryp(String str) {
        String secret = SECRET;
        try {
            Base64 base64 = new Base64();
            String ALGORITHM = "AES";
            SecretKey deskey = new SecretKeySpec(secret.getBytes("UTF-8"), ALGORITHM);// 生成密钥
            Cipher c = Cipher.getInstance(ALGORITHM);
            c.init(Cipher.DECRYPT_MODE, deskey);
            return new String(c.doFinal(base64.decode(str.getBytes("UTF-8"))), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
hx_common/src/main/java/com/hx/util/BarCodeUtil.java
New file
@@ -0,0 +1,57 @@
package com.hx.util;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import sun.misc.BASE64Encoder;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
public class BarCodeUtil {
    /**
     * 给前端产生一个条形码
     *
     * @param number 编码
     * @param width  宽度
     * @param height 高度
     */
    public static String getCode(String number, Integer width, Integer height) {
        // 生成条形码
        BufferedImage image = getBarCode(number, width, height);
        // 使用流的方式
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "png", out);
        } catch (Exception e) {
            // log.error("generate code error! error message:{}", "出现问题!");
            e.printStackTrace();
        }
        // 将流转成数组
        byte[] bytes = out.toByteArray();
        BASE64Encoder encoder = new BASE64Encoder();
        // 把生成的编码返回去
        return "data:image/png;base64," + encoder.encodeBuffer(bytes).trim();
    }
    /**
     * 产生条形码的方法
     *
     * @param number 编码
     * @param width  宽度
     * @param height 高度
     */
    public static BufferedImage getBarCode(String number, Integer width, Integer height) {
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(number, BarcodeFormat.CODE_128, width, height);
            return MatrixToImageWriter.toBufferedImage(bitMatrix);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
hx_common/src/main/java/com/hx/util/Base64Util.java
New file
@@ -0,0 +1,65 @@
package com.hx.util;
/**
 * Base64 工具类
 */
public class Base64Util {
    private static final char last2byte = (char) Integer.parseInt("00000011", 2);
    private static final char last4byte = (char) Integer.parseInt("00001111", 2);
    private static final char last6byte = (char) Integer.parseInt("00111111", 2);
    private static final char lead6byte = (char) Integer.parseInt("11111100", 2);
    private static final char lead4byte = (char) Integer.parseInt("11110000", 2);
    private static final char lead2byte = (char) Integer.parseInt("11000000", 2);
    private static final char[] encodeTable = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
    public Base64Util() {
    }
    public static String encode(byte[] from) {
        StringBuilder to = new StringBuilder((int) ((double) from.length * 1.34D) + 3);
        int num = 0;
        char currentByte = 0;
        int i;
        for (i = 0; i < from.length; ++i) {
            for (num %= 8; num < 8; num += 6) {
                switch (num) {
                    case 0:
                        currentByte = (char) (from[i] & lead6byte);
                        currentByte = (char) (currentByte >>> 2);
                    case 1:
                    case 3:
                    case 5:
                    default:
                        break;
                    case 2:
                        currentByte = (char) (from[i] & last6byte);
                        break;
                    case 4:
                        currentByte = (char) (from[i] & last4byte);
                        currentByte = (char) (currentByte << 2);
                        if (i + 1 < from.length) {
                            currentByte = (char) (currentByte | (from[i + 1] & lead2byte) >>> 6);
                        }
                        break;
                    case 6:
                        currentByte = (char) (from[i] & last2byte);
                        currentByte = (char) (currentByte << 4);
                        if (i + 1 < from.length) {
                            currentByte = (char) (currentByte | (from[i + 1] & lead4byte) >>> 4);
                        }
                }
                to.append(encodeTable[currentByte]);
            }
        }
        if (to.length() % 4 != 0) {
            for (i = 4 - to.length() % 4; i > 0; --i) {
                to.append("=");
            }
        }
        return to.toString();
    }
}
hx_common/src/main/java/com/hx/util/BigDecimalUtil.java
New file
@@ -0,0 +1,28 @@
package com.hx.util;
import java.math.BigDecimal;
public class BigDecimalUtil {
    /**保留两位小数
     *
     * @param bigDecimal 小数值
     * @return
     */
    public static BigDecimal retainDecimal(BigDecimal bigDecimal){
        bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
        return bigDecimal;
    }
    /**保留小微小数
     *
     * @param bigDecimal 小数值
     * @param decimalNum 保留小数位数
     * @return
     */
    public static BigDecimal retainDecimal(BigDecimal bigDecimal,int decimalNum){
        bigDecimal.setScale(decimalNum, BigDecimal.ROUND_HALF_UP);
        return bigDecimal;
    }
}
hx_common/src/main/java/com/hx/util/BlurDataUtil.java
New file
@@ -0,0 +1,119 @@
package com.hx.util;
import org.apache.commons.lang.StringUtils;
/**
 * 数据脱敏工具类
 *
 */
public class BlurDataUtil {
    /**
     * 手机号脱敏处理
     * 脱敏规则: 保留前三后四, 比如 18738291234 置换为 187****1234
     * @param phone
     * @return
     */
    public static final String blurPhone(String phone) {
        if (StringUtils.isEmpty(phone) || (phone.length() != 11)) {
            return phone;
        }
        return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }
    /**
     * 身份证号脱敏处理
     * 原身份证号:500222202110275699,脱敏后:132****99308084911
     * @param idCard
     * @return
     */
    public static String blurIdCard(String idCard) {
        if (StringUtils.isEmpty(idCard)) {
            return "";
        }
        /*
         * 参数1:证件号,参数2(OVERLAY):替换后的字符串,
         * 参数3(START):替换的起始下标,参数4(END):替换的结束下标(不包含)
         */
        return StringUtils.overlay(idCard, "****", 3, 7);
    }
    /**
     * 身份证号脱敏处理
     * 展示 前6位和后6位
     * @param idCard
     * @return
     */
    public static String hiddenIdCard(String idCard) {//身份证
        if (StringUtils.isBlank(idCard)) {
            return "";
        }
        return StringUtils.left(idCard, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(idCard, 4), StringUtils.length(idCard), "*"), "***"));
    }
    /**
     * 邮箱脱敏处理
     * 原邮箱:zhangsan@qq.com,脱敏后:zhang***@qq.com
     * @param email
     * @return
     */
    public static String blurEmail(String email) {
        if (StringUtils.isEmpty(email)) {
            return email;
        }
        String encrypt = email.replaceAll("(\\w+)\\w{3}@(\\w+)", "$1***@$2");
        if(StringUtils.equalsIgnoreCase(email, encrypt)){
            encrypt = email.replaceAll("(\\w*)\\w{1}@(\\w+)", "$1*@$2");
        }
        return encrypt;
    }
    /**
     * 护照脱敏处理
     * 脱敏规则:护照前2后3位脱敏,护照一般为8或9位
     * @param passport
     * @return
     */
    public static String blurPassport(String passport) {
        if (StringUtils.isEmpty(passport) || (passport.length() < 8)) {
            return passport;
        }
        return passport.substring(0, 2) + new String(new char[passport.length() - 5]).replace("\0", "*") + passport.substring(passport.length() - 3);
    }
    /**
     * 字段信息脱敏
     * 脱敏规则:如果字符长度大于3位,则隐藏最后三位,否则隐藏最后1位
     * @param field
     * @return
     */
    public static String blurField(String field) {
        if (StringUtils.isEmpty(field)) {
            return field;
        }
        String encrypt = field.replaceAll("(\\w+)\\w{3}", "$1***");
        if(StringUtils.equalsIgnoreCase(field, encrypt)){
            encrypt = field.replaceAll("(\\w*)\\w{1}", "$1*");
        }
        return encrypt;
    }
    public static void main(String[] args) {
        System.out.println(blurPhone("18738291234"));  // 187****1234
        System.out.println(blurIdCard("500222202110275699"));  // 500****99410275467
        System.out.println(blurEmail("zhangsan@qq.com"));  // zhang***@qq.com
        System.out.println(blurPassport("12345678"));  // 12***678
        System.out.println(blurField("I feel so good"));  // I f*** so g***
    }
    /*
     * 备注:
     * 1、String.replaceAll(第1个参数是脱敏筛选的正则,第2个参数是脱敏替换的正则)
     * 2、需要引入commons-lang3,这个基本每个项目都用到
     * <dependency>
     *     <groupId>org.apache.commons</groupId>
     *     <artifactId>commons-lang3</artifactId>
     *     <version>3.7</version>
     * </dependency>
     */
}
hx_common/src/main/java/com/hx/util/COSUtil.java
New file
@@ -0,0 +1,237 @@
package com.hx.util;
import com.hx.exception.TipsException;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.Download;
import com.qcloud.cos.transfer.TransferManager;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**腾讯云 COS
 * @author ChenJiaHe
 * @date 2020-12-03
 */
public class COSUtil {
    /** 后端调用上传图片
     * @param key 上传路径(包括图片名称和和后缀),指定要上传到 COS 上对象键
     * @param localFile
     * @param secretId 用户id
     * @param secretKey 用户秘钥
     * @param regionName 存在域,参考腾讯云
     * @param bucketName 指定要上传到的存储桶
     * @return
     * @throws IOException
     */
    public static String uploadImg(String key,MultipartFile localFile,String secretId, String secretKey,String regionName,String bucketName) throws IOException {
        // 1 初始化用户身份信息(secretId, secretKey)。
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        // 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(regionName);
        ClientConfig clientConfig = new ClientConfig(region);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        //开始上传
        ObjectMetadata objectMetadata = new ObjectMetadata();
        // 设置输入流长度为500
        objectMetadata.setContentLength(localFile.getSize());
        // 设置 Content type, 默认是 application/octet-stream,对于本地文件上传,默认根据本地文件的后缀进行映射
        // ,例如 jpg 文件映射 为image/jpeg对于流式上传 默认是 application/octet-stream
        //objectMetadata.setContentType("application/pdf");
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key,localFile.getInputStream(),objectMetadata);
        PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
        //拼接路径
        StringBuilder imgUrl = new StringBuilder();
        imgUrl.append("https://"+bucketName+".cos."+regionName+".myqcloud.com");
        if(key.startsWith("/")){
            imgUrl.append(key);
        }else{
            imgUrl.append("/"+key);
        }
        cosClient.shutdown();
        return imgUrl.toString();
    }
    /** 后端调用上传图片
     * @param key 上传路径(包括图片名称和和后缀),指定要上传到 COS 上对象键
     * @param localFile
     * @param secretId 用户id
     * @param secretKey 用户秘钥
     * @param regionName 存在域,参考腾讯云
     * @param bucketName 指定要上传到的存储桶
     * @return
     * @throws IOException
     */
    public static String uploadImg(String key,File localFile,String secretId, String secretKey,String regionName,String bucketName) throws IOException {
        // 1 初始化用户身份信息(secretId, secretKey)。
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        // 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(regionName);
        ClientConfig clientConfig = new ClientConfig(region);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        // 设置 Content type, 默认是 application/octet-stream,对于本地文件上传,默认根据本地文件的后缀进行映射
        // ,例如 jpg 文件映射 为image/jpeg对于流式上传 默认是 application/octet-stream
        //objectMetadata.setContentType("application/pdf");
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);
        PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
        //拼接路径
        StringBuilder imgUrl = new StringBuilder();
        imgUrl.append("https://"+bucketName+".cos."+regionName+".myqcloud.com");
        if(key.startsWith("/")){
            imgUrl.append(key);
        }else{
            imgUrl.append("/"+key);
        }
        cosClient.shutdown();
        return imgUrl.toString();
    }
    /**下载文件
     * @param key 上传路径(包括图片名称和和后缀),指定要上传到 COS 上对象键
     * @param secretId 用户id
     * @param secretKey 用户秘钥
     * @param regionName 存在域,参考腾讯云
     * @param bucketName 指定要上传到的存储桶
     */
    public static File download(String key,String secretId, String secretKey,String regionName,String bucketName){
        // 使用高级接口必须先保证本进程存在一个 TransferManager 实例,如果没有则创建
        // 详细代码参见本页:高级接口 -> 创建 TransferManager
        TransferManager transferManager = createTransferManager( secretId, secretKey,regionName);
        // 本地文件路径
        File downloadFile = null;
        try {
            GetObjectRequest getObjectRequest;
            //截取文件名称
            String[] datas = key.split(regionName+".myqcloud.com/");
            if(datas.length ==1){
                getObjectRequest = new GetObjectRequest(bucketName, datas[0]);
            }else if(datas.length ==2){
                getObjectRequest = new GetObjectRequest(bucketName, datas[1]);
            }else{
                throw new TipsException("文件路径错误【key】");
            }
            ////生成临时文件
            //获取后缀名称
            String suffix = key.substring(key.lastIndexOf("."));
            downloadFile = File.createTempFile("temp", suffix);
            // 返回一个异步结果 Donload, 可同步的调用 waitForCompletion 等待下载结束, 成功返回 void, 失败抛出异常
            Download download = transferManager.download(getObjectRequest, downloadFile);
            download.waitForCompletion();
        } catch (CosServiceException e) {
            e.printStackTrace();
        } catch (CosClientException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 确定本进程不再使用 transferManager 实例之后,关闭之
            // 详细代码参见本页:高级接口 -> 关闭 TransferManager
            shutdownTransferManager(transferManager);
        }
        return downloadFile;
    }
    /**
     * 创建 TransferManager 实例,这个实例用来后续调用高级接口
     * @param secretId
     * @param secretKey
     * @return
     */
    public static TransferManager createTransferManager(String secretId, String secretKey,String regionName) {
        // 创建一个 COSClient 实例,这是访问 COS 服务的基础实例。
        // 详细代码参见本页: 简单操作 -> 创建 COSClient
        COSClient cosClient = createCOSClient( secretId, secretKey,regionName);
        // 自定义线程池大小,建议在客户端与 COS 网络充足(例如使用腾讯云的 CVM,同地域上传 COS)的情况下,设置成16或32即可,可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况,建议减小该值,避免因网速过慢,造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);
        // 传入一个 threadpool, 若不传入线程池,默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);
        return transferManager;
    }
    /**
     * 关闭管理
     * @param transferManager
     */
    public static void shutdownTransferManager(TransferManager transferManager) {
        // 指定参数为 true, 则同时会关闭 transferManager 内部的 COSClient 实例。
        // 指定参数为 false, 则不会关闭 transferManager 内部的 COSClient 实例。
        transferManager.shutdownNow(true);
    }
    /**
     *  创建 COSClient 实例,这个实例用来后续调用请求
     * @param secretId
     * @param secretKey
     * @return
     */
    public static COSClient createCOSClient(String secretId, String secretKey,String regionName) {
        // 设置用户身份信息。
        // SECRETID 和 SECRETKEY 请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        // ClientConfig 中包含了后续请求 COS 的客户端设置:
        ClientConfig clientConfig = new ClientConfig();
        // 设置 bucket 的地域
        // COS_REGION 请参照 https://cloud.tencent.com/document/product/436/6224
        clientConfig.setRegion(new Region(regionName));
        // 设置请求协议, http 或者 https
        // 5.6.53 及更低的版本,建议设置使用 https 协议
        // 5.6.54 及更高版本,默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 以下的设置,是可选的:
        // 设置 socket 读取超时,默认 30s
        clientConfig.setSocketTimeout(300*1000);
        // 设置建立连接超时,默认 30s
        clientConfig.setConnectionTimeout(30*1000);
        // 如果需要的话,设置 http 代理,ip 以及 port
        //clientConfig.setHttpProxyIp("httpProxyIp");
        //clientConfig.setHttpProxyPort(80);
        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }
}
hx_common/src/main/java/com/hx/util/CVSUtil.java
New file
@@ -0,0 +1,56 @@
package com.hx.util;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.List;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
/**
 * CVS工具类
 *
 * @author mgchen
 *
 */
public class CVSUtil {
    public void writeToCVS() throws Exception {
        FileOutputStream fos = new FileOutputStream("E:/cjsworkspace/cjs-excel-demo/target/abc.csv");
        OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
        CSVFormat csvFormat = CSVFormat.DEFAULT.withHeader("姓名", "年龄", "家乡");
        // CSVFormat.DEFAULT.withHeader(header)
        CSVPrinter csvPrinter = new CSVPrinter(osw, csvFormat);
        // csvPrinter = CSVFormat.DEFAULT.withHeader("姓名", "年龄", "家乡").print(osw);
        for (int i = 0; i < 10; i++) {
            csvPrinter.printRecord("张三", 20, "湖北");
        }
        csvPrinter.flush();
        csvPrinter.close();
    }
    public static void writeToCVS(String path, String[] headers, List<List<Object>> data) throws Exception {
        FileOutputStream fos = new FileOutputStream(path);
        byte[] uft8bom = { (byte) 0xef, (byte) 0xbb, (byte) 0xbf };
        fos.write(uft8bom);
        OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
        CSVFormat csvFormat = CSVFormat.DEFAULT.withHeader(headers);
        CSVPrinter csvPrinter = new CSVPrinter(osw, csvFormat);
        for (int i = 0; i < data.size(); i++) {
            csvPrinter.printRecord(data.get(i));
        }
        csvPrinter.flush();
        csvPrinter.close();
        osw.close();
        fos.close();
    }
}
hx_common/src/main/java/com/hx/util/CheckCodeImageUtil.java
New file
@@ -0,0 +1,96 @@
package com.hx.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import javax.imageio.ImageIO;
/**
 * 验证码生成器
 * @author ChenJiaHe
 * @Date 2020-06-17
 */
public class CheckCodeImageUtil {
    private final static int WIDTH = 60;
    private final static int HEIGHT = 20;
    private static char[] generateCheckCode() {
        // ������֤����ַ��
        String chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        char[] rands = new char[4];
        for (int i = 0; i < 4; i++) {
            int rand = (int) (Math.random() * 35);
            rands[i] = chars.charAt(rand);
        }
        return rands;
    }
    private static void drawRands(Graphics g, char[] rands) {
        g.setColor(Color.BLACK);
        g.setFont(new Font(null, Font.ITALIC | Font.BOLD, 18));
        // �ڲ�ͬ�ĸ߶��������֤���ÿ���ַ�
        g.drawString("" + rands[0], 1, 17);
        g.drawString("" + rands[1], 16, 15);
        g.drawString("" + rands[2], 31, 18);
        g.drawString("" + rands[3], 46, 16);
    }
    private static void drawBackground(Graphics g) {
        // ������
        g.setColor(new Color(0xDCDCDC));
        g.fillRect(0, 0, WIDTH, HEIGHT);
        // ������120�����ŵ�
        for (int i = 0; i < 120; i++) {
            int x = (int) (Math.random() * WIDTH);
            int y = (int) (Math.random() * HEIGHT);
            int red = (int) (Math.random() * 255);
            int green = (int) (Math.random() * 255);
            int blue = (int) (Math.random() * 255);
            g.setColor(new Color(red, green, blue));
            g.drawOval(x, y, 1, 0);
        }
    }
    public static String[] createImage(String id)
    {
        ByteArrayOutputStream bos = null;
        String reStr = "";
        char[] rands = null;
        try {
            BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
            Graphics g = image.getGraphics();
            rands = generateCheckCode();
            drawBackground(g);
            drawRands(g, rands);
            g.dispose();
            bos = new ByteArrayOutputStream();
            ImageIO.write(image, "JPEG", bos);
            byte[] buf = bos.toByteArray();
            reStr = Base64.getEncoder().encodeToString(buf);
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(bos != null)
            {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                bos = null;
            }
        }
        return new String[] {new String(rands),reStr};
    }
}
hx_common/src/main/java/com/hx/util/CreateNoTool.java
New file
@@ -0,0 +1,46 @@
package com.hx.util;
import java.util.Random;
public class CreateNoTool {
    /**获取随机秘钥(数字与大写字母组合)
     *
     * @param y
     *            随机数位数
     * @return
     */
    public static String randomKey(Integer y) {
        String[] data = new String[] {
                "0","1","2","3","4","5","6","7","8","9"
                ,"A","B","C","D","E","F","G","H","I","J"
                ,"K","L","M","N","O","P","Q","R","S","T"
                ,"U","V","W","S","Y","Z"
        };
        String no = "";
        Random r = new Random();
        for (int i = 0; i < y; i++) {
            no += data[r.nextInt(data.length-1)];
        }
        return no;
    }
    /**获取随机秘钥(数字)
     *
     * @param y
     *            随机数位数
     * @return
     */
    public static String randomKeyNumber(Integer y) {
        String[] data = new String[] {
                "0","1","2","3","4","5","6","7","8","9"
        };
        String no = "";
        Random r = new Random();
        for (int i = 0; i < y; i++) {
            no += data[r.nextInt(data.length-1)];
        }
        return no;
    }
}
hx_common/src/main/java/com/hx/util/DateUtil.java
New file
@@ -0,0 +1,918 @@
package com.hx.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class DateUtil {
    private static SimpleDateFormat Format_1 = new SimpleDateFormat("yyyyMMdd");
    private static SimpleDateFormat Format_2 = new SimpleDateFormat("yyyyMMddHHmmss");
    private static SimpleDateFormat Format_3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static SimpleDateFormat Format_4 = new SimpleDateFormat("yyyy-MM-dd");
    private static SimpleDateFormat Format_5 = new SimpleDateFormat("HH:mm:ss");
    private static SimpleDateFormat Format_6 = new SimpleDateFormat("yyyyMM");
    private static SimpleDateFormat Format_7 = new SimpleDateFormat("MM月dd日 HH:mm");
    private static SimpleDateFormat Format_8 = new SimpleDateFormat("yyyy年MM月");
    private static SimpleDateFormat Format_9 = new SimpleDateFormat("MM-dd");
    private static SimpleDateFormat Format_10 = new SimpleDateFormat("yyyy年MM月dd日");
    private static SimpleDateFormat Format_11 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
    private static SimpleDateFormat Format_12 = new SimpleDateFormat("yyyyMMddHHmm");
    private static SimpleDateFormat Format_13 = new SimpleDateFormat("yyyy/MM/dd");
    private static SimpleDateFormat Format_14 = new SimpleDateFormat("yyyy-MM");
    private static SimpleDateFormat Format_15 = new SimpleDateFormat("yyyyMMddHHmmssSSS");
    private static SimpleDateFormat Format_16 = new SimpleDateFormat("yyyy/MM/dd HH:mm");
    private static SimpleDateFormat Format_17 = new SimpleDateFormat("HH:mm");
    /**时间格式转化iso8601
     * @param date 时间
     * @return 返回的时间格式字符串
     */
    public static String dateFormatISO8601(Date date) {
        if(!SimpleTool.checkNotNull(date)){
            return "";
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");//设置日期格式
        return df.format(date);
    }
    /**时间格式转化
     * @param date 时间
     * @param format 时间格式
     * @return 返回的时间格式字符串
     */
    public static String dateFormat(Date date, String format) {
        if(!SimpleTool.checkNotNull(date)){
            return "";
        }
        SimpleDateFormat df = new SimpleDateFormat(format);//设置日期格式
        return df.format(date);
    }
    /**时间戳转时间
     * @param timestamp 时间戳
     * @param format 时间格式
     * @return 返回的时间格式字符串
     */
    public static Date timestampToDate(long timestamp, String format) {
        SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String sd = sdf.format(new Date(timestamp));      // 时间戳转换成时间
        return DateUtil.parseString(sd,"yyyy-MM-dd HH:mm:ss");
    }
    /**
     * 转换成yyyyMMdd格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate(Date date) {
        return Format_1.format(date);
    }
    /**
     * 转换成yyyyMMddHHmmss格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_1(Date date) {
        return Format_2.format(date);
    }
    /**
     * 转换成yyyy-MM-dd HH:mm:ss格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_2(Date date) {
        return date == null ? null : Format_3.format(date);
    }
    /**
     * 转换成yyyy-MM-dd格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_3(Date date) {
        return date != null ? Format_4.format(date) : null;
    }
    /**
     * 转换成HH:mm:ss格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_4(Date date) {
        return Format_5.format(date);
    }
    /**
     * 转换成yyyyMM格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_5(Date date) {
        return Format_6.format(date);
    }
    /**
     * 转换成mm月dd日 HH:mm格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_6(Date date) {
        return Format_7.format(date);
    }
    /**
     * 转换成yyyy年mm月格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_7(Date date) {
        return Format_8.format(date);
    }
    /**
     * 转换成mm-dd格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_8(Date date) {
        return Format_9.format(date);
    }
    /**
     * 转换成yyyy年MM月dd日格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_9(Date date) {
        return Format_10.format(date);
    }
    /**
     * 转换成yyyyMMddHHmm格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_11(Date date) {
        return Format_12.format(date);
    }
    /**
     * 转换成yyyy年MM月dd日 HH:mm:ss格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_10(Date date) {
        return Format_11.format(date);
    }
    /**
     * 转换成yyyy/MM/dd 格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_13(Date date) {
        return Format_13.format(date);
    }
    /**
     * 转换成yyyy-MM 格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_14(Date date) {
        return Format_14.format(date);
    }
    /**
     * 当前时间之前的时间与当前时间相差多少秒
     * @param startDate 当前时间之前的时间
     * @return
     */
    public static int calLastedTime(Date startDate) {
        long nowDate = new Date().getTime();
        long startDateTime = startDate.getTime();
        int diffSeconds = (int) ((nowDate - startDateTime) / 1000);
        return diffSeconds;
    }
    /**
     * 转换成yyyyMMddHHmmssSSS格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_15(Date date) {
        return Format_15.format(date);
    }
    /**
     * 转换成yyyy/MM/dd HH:mm格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_16(Date date) {
        return Format_16.format(date);
    }
    /**
     * 转换成HH:mm格式的日期字符串
     *
     * @param date
     * @return
     */
    public static String formatDate_17(Date date) {
        return Format_17.format(date);
    }
    /**
     * 转换成字符串yyyyMMddHHmmss成日�?
     *
     * @param str
     * @return
     * @throws Exception
     */
    public static Date parseString(String str) {
        try {
            return Format_2.parse(str);
        }catch (Exception e)
        {
            return null;
        }
    }
    /**
     * 转换成字符串到指定的日期
     *
     * @param str
     * @param format
     * @return
     * @throws Exception
     */
    public static Date parseString(String str, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try{
            return sdf.parse(str);
        }catch (Exception e)
        {
            return null;
        }
    }
    /**字符串转成时间yyyy-MM-dd HH:mm:ss*/
    public static Date parseString_1(String str)
    {
        try{
            return  Format_3.parse(str);
        }catch (Exception e)
        {
            return null;
        }
    }
    /**字符串转成时间yyyy-MM-dd*/
    public static Date parseString_2(String str)
    {
        try{
            return Format_4.parse(str);
        }catch (Exception e)
        {
            return null;
        }
    }
    /**时间上秒叠加
     * @Author: ChenJiaHe
     * @param dateTime 时间
     * @param second 秒
     * @return
     */
    public static Date addSecond(Date dateTime,int second){
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.SECOND, second);
        return c.getTime();
    }
    /**时间上分钟叠加
     * @Author: ChenJiaHe
     * @param dateTime 时间
     * @param min 分钟
     * @return
     */
    public static Date addMin(Date dateTime,int min){
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.MINUTE, min);
        return c.getTime();
    }
    /**时间上小时叠加
     * @Author: ChenJiaHe
     * @param dateTime 时间
     * @param hour 小时
     * @return
     */
    public static Date addhour(Date dateTime,int hour){
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.HOUR, hour);
        return c.getTime();
    }
    /**时间上天数叠加
     * @Author: ChenJiaHe
     * @param dateTime 时间
     * @param dayNum 天数
     * @return
     */
    public static Date addDay(Date dateTime,int dayNum){
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.DATE, dayNum);
        return c.getTime();
    }
    /**时间上月数叠加
     * @Author: ChenJiaHe
     * @param dateTime 时间
     * @param dayNum 天数
     * @return
     */
    public static Date addMonth(Date dateTime,int dayNum){
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.MONTH, dayNum);
        return c.getTime();
    }
    /**时间上年数叠加
     * @Author: ChenJiaHe
     * @param dateTime 时间
     * @param dayNum 天数
     * @return
     */
    public static Date addYear(Date dateTime,int dayNum){
        Calendar c = Calendar.getInstance();
        c.setTime(dateTime);
        c.add(Calendar.YEAR, dayNum);
        return c.getTime();
    }
    /**
     * 转换成字符串到指定的日期
     *
     * @param date
     * @param format
     * @return
     * @throws Exception
     */
    public static String formatDate(Date date, String format) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.CHINA);
        return sdf.format(date);
    }
    /**日期转星期
     * @param dateTime 字符串时间
     * @param format 字符串时间格式
     * @param returnType 返回类型 0星期几1周几
     * @return 数据
     */
    public static String dateToWeek(String dateTime,String format,Integer returnType) throws ParseException {
        SimpleDateFormat f = new SimpleDateFormat(format);
        String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
        if(SimpleTool.checkNotNull(returnType)&&returnType==1){
            weekDays  = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        }
        Calendar cal = Calendar.getInstance(); // 获得一个日历
        Date datet = null;
        datet = f.parse(dateTime);
        cal.setTime(datet);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
        if (w < 0)
            w = 0;
        return weekDays[w];
    }
    /**日期转星期
     * @param dateTime 时间
     * @param returnType 返回类型 0星期几1周几
     * @return 数据
     */
    public static String dateToWeek(Date dateTime,Integer returnType) {
        String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
        if(SimpleTool.checkNotNull(returnType)&&returnType==1){
            weekDays  = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        }
        Calendar cal = Calendar.getInstance(); // 获得一个日历
        cal.setTime(dateTime);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
        if (w < 0)
            w = 0;
        return weekDays[w];
    }
    /**
     * 获取两个时间相差分钟数
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 分钟
     */
    public static long differMinute(Date startTime, Date endTime) {
        long NTime = startTime.getTime();
        long OTime = endTime.getTime();
        return (NTime - OTime) / 1000 / 60;
    }
    /**
     * 获取两个时间相差分钟数
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param remainder 余数进1
     * @return 分钟
     */
    public static int differMinute(Date startTime, Date endTime,boolean remainder) {
        BigDecimal sTime = new BigDecimal(startTime.getTime());
        BigDecimal eTime = new BigDecimal(endTime.getTime());
        eTime = eTime.subtract(sTime).setScale(0,RoundingMode.HALF_UP);
        if(remainder){
            eTime = eTime.divide(BigDecimal.valueOf(60000.0)).setScale(0, RoundingMode.UP);
        }else{
            eTime = eTime.divide(BigDecimal.valueOf(60000.0)).setScale(0, RoundingMode.DOWN);
        }
        return eTime.intValue();
    }
    /**
     * endTime比startTime多的天数
     * @param startTime 最小时间
     * @param endTime 最大时间
     * @return 返回
     */
    public static Integer differDay(Date startTime,Date endTime){
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(startTime);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(endTime);
        int day1= cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);
        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if(year1 != year2) { //同一年
            int timeDistance = 0 ;
            for(int i = year1 ; i < year2 ; i ++) {
                if(i%4==0 && i%100!=0 || i%400==0) {//闰年
                    timeDistance += 366;
                }
                else {//不是闰年
                    timeDistance += 365;
                }
            }
            return timeDistance + (day2-day1) ;
        }
        else { //不同年
            System.out.println("判断day2 - day1 : " + (day2-day1));
            return day2-day1;
        }
    }
    /**判断两个时间是不是同一天*/
    public static boolean timeEqual(Date startTime,Date endTime){
       if(startTime == null || endTime==null){
           return false;
       }
       boolean status = false;
       if(formatDate(startTime,"yyyyMMdd").equals(formatDate(endTime,"yyyyMMdd"))){
           status = true;
       }
       return status;
    }
    /**把秒转换成X天X时X分X秒*/
    public static String getChineseStr(Integer second) {
        int day = 24 * 60 * 60;
        int hour = 60 * 60;
        int min = 60;
        int dayNum = second / day;
        int hourNum = second % day / hour;
        int minNum = second % day % hour / min;
        second = second % day % hour % min;
        String str = dayNum > 0 ? dayNum + "天" : "";
        str += hourNum > 0 ? hourNum + "时" : "";
        str += minNum > 0 ? minNum + "分" : "";
        str += second + "秒";
        return str;
    }
    /**
     * 针对str格式的时间做转换 格式为"xx:xx"
     * @param time  传入的时间
     * @return  返回分钟如果10:25,则返回625
     */
    public static int getMinuteNum(String time){
        if(!StringUtils.isEmpty(time))
        {
            String[] arr = time.split(":");
            if(arr != null && arr.length == 2)
            {
                return Integer.parseInt(arr[0]) * 60 + Integer.parseInt(arr[1]);
            }
        }
        return 0;
    }
    /**
     * 获取当前月的开始时间
     * @param time 时间
     * @return 返回时间 格式yyyy-MM-dd 00:00:00
     */
    public static Date getMonthStart(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND,0);
        return calendar.getTime();
    }
    /**
     * 获取当前月的开始时间
     *
     * @param num 0拿取当月,正代表后,负代表前,值为几个(月)
     * @return 返回时间 格式yyyy-MM-dd 00:00:00
     */
    public static String getMonthStart(Integer num) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, num);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
        return sdf.format(calendar.getTime());
    }
    /**
     * 获取当前月的结束时间
     * @param date 点前时间
     * @return 返回时间 格式yyyy-MM-dd 23:59:59999
     */
    public static Date getMonthEnd(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND,999);
        return calendar.getTime();
    }
    /**
     * 获取当前月的结束时间,没有毫秒
     * @param date 点前时间
     * @return 返回时间 格式yyyy-MM-dd 23:59:59
     */
    public static Date getMonthEndNoMillisecond(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }
    /**
     * 获取当前月的结束时间
     * @param num 0拿取当月,正代表后,负代表前,值为几个(月)
     * @return 返回时间 格式yyyy-MM-dd 23:59:59
     */
    public static String getMonthEnd(Integer num) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, num);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
        return sdf.format(calendar.getTime());
    }
    /**
     * 获取当前年的开始时间
     * @param time 时间
     * @return 返回时间 格式yyyy-MM-dd 00:00:00
     */
    public static Date getYearStart(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND,0);
        return calendar.getTime();
    }
    /**
     * 获取当前年的结束时间
     * @param time 时间
     * @return 返回时间 格式yyyy-MM-dd 23:59:59999
     */
    public static Date getYearEnd(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.set(Calendar.MONTH, 11);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DATE));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND,999);
        return calendar.getTime();
    }
    /**
     * 获取当前年的结束时间,没有毫秒
     * @param time 时间
     * @return 返回时间 格式yyyy-MM-dd 23:59:59
     */
    public static Date getYearEndNoMillisecond(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.set(Calendar.MONTH, 11);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DATE));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }
    /**这天的开始时间
     * 日期2000-01-01变2000-01-01 00:00:00
     */
    public static String dayToStart(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
        return sdf.format(calendar.getTime());
    }
    /**这天的最后时间
     * 日期2000-01-01变2000-01-01 23:59:59
     */
    public static String dayToEnd(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
        return sdf.format(calendar.getTime());
    }
    /**这天的开始时间
     * 日期2000-01-01变2000-01-01 00:00:00
     */
    public static Date dayToStartDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }
    /**这天的最后时间
     * 日期2000-01-01变2000-01-01 23:59:59999
     */
    public static Date dayToEndDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }
    /**这天的最后时间,没有毫秒
     * 日期2000-01-01变2000-01-01 23:59:59
     */
    public static Date dayToEndDateNoMillisecond(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }
    /**获取月份的天数
     * @param date 时间
     * @return 月份的天数
     */
    public static int getMonthDays(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        cal.roll(Calendar.DATE, -1);
        return cal.getActualMaximum(Calendar.DATE);
    }
    /**获取月份的天数
     * @param year 年份
     * @param month 月份
     * @return 月份的天数
     */
    public static int getMonthDays(int year, int month) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, (month - 1));
        cal.set(Calendar.DATE, 1);
        cal.roll(Calendar.DATE, -1);
        return cal.getActualMaximum(Calendar.DATE);
    }
    /**获取月份的天数
     * @param yearMonth 年月
     * @param format 时间格式
     * @return 返回
     */
    public static int getMonthDays(String yearMonth,String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(sdf.parse(yearMonth));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }
    /**当天多少点前
     * @param date 时间
     * @param num 多少点前,不含当点前,24小时制
     * @return 月份的天数
     */
    public static boolean getFrontMinute(Date date,int num) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, num-1);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        return date.compareTo(cal.getTime()) < 1;
    }
    /**
     * 获得某个日期的当天某点
     * 例如:2022-12-26 11:20:00 -> 2022-12-26 13:00:00
     * @param num 24小时
     */
    public static String getHourDayTime(Date date,int num) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, num);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
        return sdf.format(calendar.getTime());
    }
    /**
     * 获取时间当月剩余天数
     * */
    public static Integer getMonthSurplus(Date date) {
        Calendar month = Calendar.getInstance();
        month.setTime(new Date());
        month.set(Calendar.DATE, 1);
        month.roll(Calendar.DATE, -1);
        return month.getActualMaximum(Calendar.DATE) - Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
    }
    /**获取当前时间所在周的周一00:00:00*/
    public static Date getMonday(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        //以周一为首日
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        //周一
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return calendar.getTime();
    }
    /**
     * 根据出生年月日计算年龄
     * @param birth
     * @return
     */
    public static int getAge(Date birth) {
        Calendar cal = Calendar.getInstance();
        int thisYear = cal.get(Calendar.YEAR);
        int thisMonth = cal.get(Calendar.MONTH);
        int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
        cal.setTime(birth);
        int birthYear = cal.get(Calendar.YEAR);
        int birthMonth = cal.get(Calendar.MONTH);
        int birthdayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
        int age = thisYear - birthYear;
        // 未足月
        if (thisMonth <= birthMonth) {
            // 当月
            if (thisMonth == birthMonth) {
                // 未足日
                if (dayOfMonth < birthdayOfMonth) {
                    age--;
                }
            } else {
                age--;
            }
        }
        return age;
    }
    /**
     * 获取某天结束秒数
     * @param dateTime      日期
     * @param lateSecond    延迟秒数
     * @return
     */
    public static long todayEndSecond(Date dateTime, Long lateSecond) {
        if(dateTime == null){
            dateTime = new Date();
        }
        if(lateSecond == null){
            lateSecond = 0L;
        }
        Date endTime = DateUtil.dayToEndDate(dateTime);
        return differSecond(dateTime, endTime) + lateSecond;
    }
    /**
     * 计算2个实际相差秒数
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static long differSecond(Date startTime, Date endTime) {
        if(startTime == null || endTime == null){
            return 0L;
        }
        long sTime = startTime.getTime();
        long eTime = endTime.getTime();
        return (eTime - sTime) / 1000L;
    }
}
hx_common/src/main/java/com/hx/util/DownFileUtil.java
New file
@@ -0,0 +1,225 @@
package com.hx.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
public class DownFileUtil {
    /**
     * 下载文件工具
     *
     * @param path
     *            完整路径(可用simpleToof工具获取)
     */
    public static void DownFile(HttpServletRequest request,HttpServletResponse  response,String path) {
        final String userAgent = request.getHeader("USER-AGENT");
        try {
            // AdminUpload adminUpload = dm.find(AdminUpload.class, fileName);
            // String str =adminUpload.getPath();
            String filePath = path;
            // System.out.println("path"+ServletActionContext.getRequest().getRealPath("/")
            // + filePath);
            // File downfile = new
            // File(ServletActionContext.getRequest().getRealPath("/") +
            // filePath);
            File downfile = new File(filePath);
            String filename = "";
            if(userAgent.equals("MSIE")){//IE浏览器
                filename = URLEncoder.encode(downfile.getName(),"UTF8");
            }else if(userAgent.equals("Mozilla")){//google,火狐浏览器
                filename = new String(downfile.getName().getBytes(), "ISO8859-1");
            }else{
                filename = URLEncoder.encode(downfile.getName(),"UTF8");//其他浏览器
            }
            InputStream fis = new BufferedInputStream(new FileInputStream(
                    downfile));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.reset();
            response.addHeader("Content-Disposition",
                    "attachment;filename=" + filename);
            response.addHeader("Content-Length",
                    "" + downfile.length());
            OutputStream toClient = new BufferedOutputStream(
                    response.getOutputStream());
            response.setContentType(
                    "application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 下载文件工具(提示选择路径)
     *
     * @param path
     *            完整路径(可用simpleToof工具获取)
     */
    public static void DownFileTips(HttpServletRequest request,HttpServletResponse response,String path) {
        final String userAgent = request.getHeader("USER-AGENT");
        try {
            // AdminUpload adminUpload = dm.find(AdminUpload.class, fileName);
            // String str =adminUpload.getPath();
            String filePath = path;
            // System.out.println("path"+ServletActionContext.getRequest().getRealPath("/")
            // + filePath);
            // File downfile = new
            // File(ServletActionContext.getRequest().getRealPath("/") +
            // filePath);
            File downfile = new File(filePath);
            String filename = "";
            if(userAgent.equals("MSIE")){//IE浏览器
                filename = URLEncoder.encode(downfile.getName(),"UTF8");
            }else if(userAgent.equals("Mozilla")){//google,火狐浏览器
                filename = new String(downfile.getName().getBytes(), "ISO8859-1");
            }else{
                filename = URLEncoder.encode(downfile.getName(),"UTF8");//其他浏览器
            }
            InputStream fis = new BufferedInputStream(new FileInputStream(
                    downfile));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.addHeader("Content-Disposition", "attachment;filename="+ new String(filename.getBytes()));
            OutputStream toClient= new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 下载文件工具(提示选择路径)
     *
     * @param downfile
     *            导出的文件
     * @param fileName
     *            导出的文件名称
     */
    public static void DownFileTips(HttpServletRequest request, HttpServletResponse response, File downfile, String fileName) {
        final String userAgent = request.getHeader("USER-AGENT");
        try {
            if(StringUtils.isEmpty(fileName)){
                fileName = downfile.getName();
            }
            String filename =  "";
            if(userAgent.equals("MSIE")){//IE浏览器
                filename = URLEncoder.encode(fileName,"UTF8");
            }else if(userAgent.equals("Mozilla")){//google,火狐浏览器
                filename = new String(fileName.getBytes(), "ISO8859-1");
            }else{
                filename = URLEncoder.encode(fileName,"UTF8");//其他浏览器
            }
            InputStream fis = new BufferedInputStream(new FileInputStream(
                    downfile));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.addHeader("Content-Disposition", "attachment;filename="+ filename);
            OutputStream toClient= new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 下载文件工具(提示选择路径)
     *
     * @param inputStream
     *            导出的文件流
     * @param fileName
     *            导出的文件名称
     */
    public static void DownFileTips(HttpServletRequest request, HttpServletResponse response, InputStream  inputStream , String fileName) {
        final String userAgent = request.getHeader("USER-AGENT");
        try {
            if(StringUtils.isEmpty(fileName)){
                throw new RuntimeException("请输入文件名称");
            }
            String filename =  "";
            if(userAgent.equals("MSIE")){//IE浏览器
                filename = URLEncoder.encode(fileName,"UTF8");
            }else if(userAgent.equals("Mozilla")){//google,火狐浏览器
                filename = new String(fileName.getBytes(), "ISO8859-1");
            }else{
                filename = URLEncoder.encode(fileName,"UTF8");//其他浏览器
            }
            InputStream fis = new BufferedInputStream(inputStream);
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.addHeader("Content-Disposition", "attachment;filename="+ filename);
            OutputStream toClient= new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 下载文件工具(提示选择路径)
     *
     * @param downfile
     *            导出的文件
     * @param fileName
     *            导出的文件名称
     */
    public static void DownFileTips( HttpServletResponse response, File downfile, String fileName) {
        try {
            if(StringUtils.isEmpty(fileName)){
                fileName = downfile.getName();
            }
            String filename =  "";
            filename = URLEncoder.encode(fileName,"UTF8");//其他浏览器
            InputStream fis = new BufferedInputStream(new FileInputStream(
                    downfile));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.addHeader("Content-Disposition", "attachment;filename="+ filename);
            OutputStream toClient= new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
hx_common/src/main/java/com/hx/util/EmailUtil.java
New file
@@ -0,0 +1,120 @@
package com.hx.util;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.Properties;
/**邮件处理工具
 * @author ChenJiaHe
 * @Date 2020-07-06
 */
public class EmailUtil {
    /**
     * 发送带附件的邮件
     *
     * @param receive
     *            收件人
     * @param subject
     *            邮件主题
     * @param msg
     *            邮件内容
     * @param filename
     *            附件地址
     * @param from
     *            发件人电子邮箱
     * @param pass
     *            发件人电子邮箱密码
     * @return
     * @throws GeneralSecurityException
     */
    public static boolean sendMail(String receive, String subject, String msg, String filename,
                                   String from,String pass)
            throws GeneralSecurityException {
        if (StringUtils.isEmpty(receive)) {
            return false;
        }
        // 指定发送邮件的主机为 smtp.qq.com   smtp.163.com
        String host = "smtp.qq.com"; // 邮件服务器
        // 获取系统属性
        Properties properties = System.getProperties();
        // 设置邮件服务器
        properties.setProperty("mail.smtp.host", host);
        properties.put("mail.smtp.auth", "true");
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        properties.put("mail.smtp.ssl.enable", "true");
        properties.put("mail.smtp.ssl.socketFactory", sf);
        // 获取默认session对象
        Session session = Session.getDefaultInstance(properties, new Authenticator() {
            public PasswordAuthentication getPasswordAuthentication() { // qq邮箱服务器账户、第三方登录授权码
                return new PasswordAuthentication(from, pass); // 发件人邮件用户名、密码
            }
        });
        try {
            // 创建默认的 MimeMessage 对象
            MimeMessage message = new MimeMessage(session);
            // Set From: 头部头字段
            message.setFrom(new InternetAddress(from));
            // Set To: 头部头字段
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(receive));
            // Set Subject: 主题文字
            message.setSubject(subject);
            // 创建消息部分
            BodyPart messageBodyPart = new MimeBodyPart();
            // 消息
            messageBodyPart.setText(msg);
            // 创建多重消息
            Multipart multipart = new MimeMultipart();
            // 设置文本消息部分
            multipart.addBodyPart(messageBodyPart);
            // 附件部分
            messageBodyPart = new MimeBodyPart();
            // 设置要发送附件的文件路径
            if(SimpleTool.checkNotNull(filename)){
                DataSource source = new FileDataSource(filename);
                if(!SimpleTool.checkNotNull(source)){
                    throw new RuntimeException("获取附件失败!");
                }
                messageBodyPart.setDataHandler(new DataHandler(source));
                // messageBodyPart.setFileName(filename);
                // 处理附件名称中文(附带文件路径)乱码问题
                //messageBodyPart.setFileName(MimeUtility.encodeText(source.getName()));
                messageBodyPart.setFileName(new String(source.getName().toString().getBytes("UTF-8")));
                multipart.addBodyPart(messageBodyPart);
            }
            // 发送完整消息
            message.setContent(multipart);
            // 发送消息
            Transport.send(message);
            // System.out.println("Sent message successfully....");
            return true;
        } catch (MessagingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return false;
    }
}
hx_common/src/main/java/com/hx/util/ExcelFileUtil.java
New file
@@ -0,0 +1,129 @@
package com.hx.util;
import com.hx.exception.TipsException;
import jxl.CellType;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
 * Excel工具类(兼容poi4.0+)
 */
public class ExcelFileUtil {
    /**
     * 读取 Excel文件内容
     *
     * @param file
     * @param header 是否包括表头
     * @return
     * @throws Exception
     */
    public static List<List<String>> readExcelByeFileData(MultipartFile file, boolean header) throws Exception {
        // 结果集
        List<List<String>> list = new ArrayList<>();
        if (file == null){
            return list;
        }
        String fileName = file.getOriginalFilename();
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            throw new TipsException("上传文件格式不正确");
        }
        Workbook hssfworkbook = WorkbookFactory.create(file.getInputStream());
        int num = hssfworkbook.getNumberOfSheets();
        if (num == 0){
            return list;
        }
        List<String> rowList;
        for (int k = 0; k< num ; k++) {
            Sheet sheet = hssfworkbook.getSheetAt(k);
            for (int i = 0; i <= sheet.getLastRowNum(); i++) {
                rowList = new ArrayList<>();
                // 获取第i行的数据
                Row row = sheet.getRow(i);
                // getLastCellNum() 获取这一行中单元格的数量
                for (int j = 0; j < row.getLastCellNum(); j++) {
                    // 获取第i行第j列的单元格数据
                    rowList.add(row.getCell(j).toString());
                }
                list.add(rowList);
            }
        }
        return list;
    }
    /**
     * 读取 Excel文件内容
     *
     * @param file
     * @param header 是否包括表头
     * @return
     * @throws Exception
     */
    public static List<List<String>> readExcelByeFileData(File file, boolean header) throws Exception {
        // 结果集
        List<List<String>> list = new ArrayList<>();
        if (file == null){
            return list;
        }
        String fileName = file.getName();
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            throw new TipsException("上传文件格式不正确");
        }
        Workbook hssfworkbook = WorkbookFactory.create(new FileInputStream(file));
        int num = hssfworkbook.getNumberOfSheets();
        if (num == 0){
            return list;
        }
        List<String> rowList;
        for (int k = 0; k< num ; k++) {
            Sheet sheet = hssfworkbook.getSheetAt(k);
            for (int i = 0; i <= sheet.getLastRowNum(); i++) {
                rowList = new ArrayList<>();
                // 获取第i行的数据
                Row row = sheet.getRow(i);
                // getLastCellNum() 获取这一行中单元格的数量
                for (int j = 0; j < row.getLastCellNum(); j++) {
                    // 获取第i行第j列的单元格数据
                    rowList.add(row.getCell(j).toString());
                }
                list.add(rowList);
            }
        }
        return list;
    }
    private static String objToString(Object obj) {
        if (obj == null) {
            return "";
        } else {
            if (obj instanceof String) {
                return (String) obj;
            } else if (obj instanceof Date) {
                return null;
            } else {
                return obj.toString();
            }
        }
    }
}
hx_common/src/main/java/com/hx/util/ExcelUtil.java
New file
@@ -0,0 +1,1133 @@
package com.hx.util;
import com.hx.exception.TipsException;
import com.monitorjbl.xlsx.StreamingReader;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
 *
 * @author hjr
 */
public final class ExcelUtil {
    /**
     * @param excelName
     *         文件名称
     * @param outPath
     *             保存路径
     * @param headList
     *        Excel文件Head标题集合
     * @param fieldList
     *        Excel文件Field标题集合 根据field来寻找位置填充表格
     * @param dataList
     *        Excel文件数据内容部分
     * @throws Exception
     */
    public static String createExcel(String outPath, String excelName,
                                     String[] headList, String[] fieldList,
                                     List<Map<String, Object>> dataList) throws Exception {
        String filePath = null;
        // 创建新的Excel 工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 在Excel工作簿中建一工作表,其名为缺省值
        // 如要新建一名为"效益指标"的工作表,其语句为:
        // HSSFSheet sheet = workbook.createSheet("效益指标");
        HSSFSheet sheet = workbook.createSheet();
        // 在索引0的位置创建行(最顶端的行)
        HSSFRow row = sheet.createRow(0);
        // ===============================================================
        HSSFCell cell;
        for (int i = 0; i < headList.length; i++) {
            // 在索引0的位置创建单元格(左上端)
            cell = row.createCell(i);
            // 定义单元格为字符串类型
            //cell.setCellType(HSSFCell.CELL_TYPE_STRING);
            // 在单元格中输入一些内容
            cell.setCellValue(headList[i]);
        }
        // ===============================================================
        if (dataList != null) {
            HSSFRow row_value;
            Map<String, Object> dataMap;
            for (int n = 0; n < dataList.size(); n++) {
                // 在索引1的位置创建行
                row_value = sheet.createRow(n + 1);
                dataMap = dataList.get(n);
                // ===============================================================
                for (int i = 0; i < fieldList.length; i++) {
                    // 在索引0的位置创建单元格(左上端)
                    cell = row_value.createCell(i);
                    // 定义单元格为字符串类型
                    //cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                    // 在单元格中输入一些内容
                    cell.setCellValue(objToString(dataMap.get(fieldList[i])));
                }
                // ===============================================================
            }
        }
        // 新建一输出文件流
        File file = SimpleTool.createFile(outPath, excelName);
        FileOutputStream fOut = new FileOutputStream(file);
        // 把相应的Excel 工作簿存盘
        workbook.write(fOut);
        fOut.flush();
        // 操作结束,关闭文件
        fOut.close();
        if(outPath.endsWith("/")){
            filePath = outPath + excelName;
        }else{
            filePath = outPath +"/"+ excelName;
        }
        return filePath;
    }
    /**生成临时文件
     * @param headList
     *        Excel文件Head标题集合
     * @param fieldList
     *        Excel文件Field标题集合 根据field来寻找位置填充表格
     * @param dataList
     *        Excel文件数据内容部分
     * @throws Exception
     */
    public static File createExcel(String[] headList, String[] fieldList,
                                   List<Map<String, Object>> dataList) throws Exception {
        File file = File.createTempFile("temp", ".xlsx");
        try{
            // 创建新的Excel 工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            // 在Excel工作簿中建一工作表,其名为缺省值
            // 如要新建一名为"效益指标"的工作表,其语句为:
            // HSSFSheet sheet = workbook.createSheet("效益指标");
            HSSFSheet sheet = workbook.createSheet();
            // 在索引0的位置创建行(最顶端的行)
            HSSFRow row = sheet.createRow(0);
            // ===============================================================
            HSSFCell cell;
            for (int i = 0; i < headList.length; i++) {
                // 在索引0的位置创建单元格(左上端)
                cell = row.createCell(i);
                // 定义单元格为字符串类型
                //cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                // 在单元格中输入一些内容
                cell.setCellValue(headList[i]);
            }
            // ===============================================================
            if (dataList != null) {
                HSSFRow row_value;
                Map<String, Object> dataMap;
                for (int n = 0; n < dataList.size(); n++) {
                    // 在索引1的位置创建行
                    row_value = sheet.createRow(n + 1);
                    dataMap = dataList.get(n);
                    // ===============================================================
                    for (int i = 0; i < fieldList.length; i++) {
                        // 在索引0的位置创建单元格(左上端)
                        cell = row_value.createCell(i);
                        // 定义单元格为字符串类型
                        //cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                        // 在单元格中输入一些内容
                        cell.setCellValue(objToString(dataMap.get(fieldList[i])));
                    }
                    // ===============================================================
                }
            }
            // 新建一输出文件流
            FileOutputStream fOut = new FileOutputStream(file);
            // 把相应的Excel 工作簿存盘
            workbook.write(fOut);
            fOut.flush();
            // 操作结束,关闭文件
            fOut.close();
        }catch (Exception e){
        }finally {
            file.deleteOnExit();
        }
        return file;
    }
    /**生成临时文件
     * @param headList
     *        Excel文件Head标题集合
     * @param fieldList
     *        Excel文件Field标题集合 根据field来寻找位置填充表格
     * @param dataList
     *        Excel文件数据内容部分
     * @throws Exception
     */
    public static File createExcel(String[] headList, String[] fieldList, List<Map<String, Object>> dataList
            ,Integer height,Integer width) throws Exception {
        File file = File.createTempFile("temp", ".xls");
        try{
            if(height == null){
                height = 450;
            }
            if(width == null){
                width = 5000;
            }
            // 创建新的Excel 工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            //合并的单元格样式
            HSSFCellStyle boderStyle = workbook.createCellStyle();
            //垂直居中
            boderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            boderStyle.setAlignment(HorizontalAlignment.CENTER); // 创建一个居中格式
            // 在Excel工作簿中建一工作表,其名为缺省值
            // 如要新建一名为"效益指标"的工作表,其语句为:
            // HSSFSheet sheet = workbook.createSheet("效益指标");
            HSSFSheet sheet = workbook.createSheet();
            // 在索引0的位置创建行(最顶端的行)
            HSSFRow row = sheet.createRow(0);
            // ===============================================================
            HSSFCell cell;
            for (int i = 0; i < headList.length; i++) {
                //高度
                row.setHeight(height.shortValue());
                sheet.setColumnWidth(i,width);
                // 在索引0的位置创建单元格(左上端)
                cell = row.createCell(i);
                // 定义单元格为字符串类型
                //cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                // 在单元格中输入一些内容
                cell.setCellValue(headList[i]);
                cell.setCellStyle(boderStyle);
            }
            // ===============================================================
            if (dataList != null) {
                HSSFRow row_value;
                Map<String, Object> dataMap;
                for (int n = 0; n < dataList.size(); n++) {
                    // 在索引1的位置创建行
                    row_value = sheet.createRow(n + 1);
                    row_value.setHeight(height.shortValue());
                    dataMap = dataList.get(n);
                    // ===============================================================
                    for (int i = 0; i < fieldList.length; i++) {
                        // 在索引0的位置创建单元格(左上端)
                        sheet.setColumnWidth(i,width);
                        cell = row_value.createCell(i);
                        // 定义单元格为字符串类型
                        //cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                        // 在单元格中输入一些内容
                        cell.setCellValue(objToString(dataMap.get(fieldList[i])));
                        cell.setCellStyle(boderStyle);
                    }
                    // ===============================================================
                }
            }
            // 新建一输出文件流
            FileOutputStream fOut = new FileOutputStream(file);
            // 把相应的Excel 工作簿存盘
            workbook.write(fOut);
            fOut.flush();
            // 操作结束,关闭文件
            fOut.close();
        }catch (Exception e){
        }finally {
            file.deleteOnExit();
        }
        return file;
    }
    /**无限制行数生成ecxel,生成临时文件
     * @param headList
     *        Excel文件Head标题集合
     * @param fieldList
     *        Excel文件Field标题集合 根据field来寻找位置填充表格
     * @param dataList
     *        Excel文件数据内容部分
     * @param height  单元格高度,默认450
     * @param width  单元格宽度,默认5000
     * @throws Exception
     */
    public static File createXSSExcel(String[] headList, String[] fieldList, List<Map<String, Object>> dataList
            ,Integer height,Integer width) throws Exception {
        File file = File.createTempFile("temp", ".xls");
        try{
            if(height == null){
                height = 450;
            }
            if(width == null){
                width = 5000;
            }
            // 创建新的Excel 工作簿
            //XSSFWorkbook workbook = new XSSFWorkbook();
            SXSSFWorkbook workbook = new SXSSFWorkbook(1000);
            //合并的单元格样式
            CellStyle boderStyle = workbook.createCellStyle();
            //垂直居中
            boderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            boderStyle.setAlignment(HorizontalAlignment.CENTER); // 创建一个居中格式
            // 在Excel工作簿中建一工作表,其名为缺省值
            // 如要新建一名为"效益指标"的工作表,其语句为:
            // HSSFSheet sheet = workbook.createSheet("效益指标");
            Sheet sheet = workbook.createSheet();
            // 在索引0的位置创建行(最顶端的行)
            Row row = sheet.createRow(0);
            // ===============================================================
            Cell cell;
            for (int i = 0; i < headList.length; i++) {
                //高度
                row.setHeight(height.shortValue());
                sheet.setColumnWidth(i,width);
                // 在索引0的位置创建单元格(左上端)
                cell = row.createCell(i);
                // 定义单元格为字符串类型
                //cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                // 在单元格中输入一些内容
                cell.setCellValue(headList[i]);
                cell.setCellStyle(boderStyle);
            }
            // ===============================================================
            if (dataList != null) {
                Row row_value;
                Map<String, Object> dataMap;
                for (int n = 0; n < dataList.size(); n++) {
                    // 在索引1的位置创建行
                    row_value = sheet.createRow(n + 1);
                    row_value.setHeight(height.shortValue());
                    dataMap = dataList.get(n);
                    // ===============================================================
                    for (int i = 0; i < fieldList.length; i++) {
                        // 在索引0的位置创建单元格(左上端)
                        sheet.setColumnWidth(i,width);
                        cell = row_value.createCell(i);
                        // 定义单元格为字符串类型
                        //cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                        // 在单元格中输入一些内容
                        cell.setCellValue(objToString(dataMap.get(fieldList[i])));
                        cell.setCellStyle(boderStyle);
                    }
                    // ===============================================================
                }
            }
            // 新建一输出文件流
            FileOutputStream fOut = new FileOutputStream(file);
            // 把相应的Excel 工作簿存盘
            workbook.write(fOut);
            fOut.flush();
            // 操作结束,关闭文件
            fOut.close();
        }catch (Exception e){
        }finally {
            file.deleteOnExit();
        }
        return file;
    }
    private static String objToString(Object obj) {
        if (obj == null) {
            return "";
        } else {
            if (obj instanceof String) {
                return (String) obj;
            } else if (obj instanceof Date) {
                return null;// DateUtil.dateToString((Date)
                // obj,DateUtil.DATESTYLE_SHORT_EX);
            } else {
                return obj.toString();
            }
        }
    }
    /**
     * 读取Excel数据
     * @param file
     * @param header
     * @return
     * @throws Exception
     */
    public static List<List<String>> readExcelData(MultipartFile file, boolean header) throws Exception {
        String fileName = file.getOriginalFilename();
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            throw new TipsException("上传文件格式不正确");
        }
        //判断不同格式处理方法不同
        if(fileName.matches("^.+\\.(?i)(xls)$")){
            //xls格式使用HSSF
            return readExcelByeFileData(file, header);
        }else{
            //xlsx格式使用XSSF
            return readExcelByeFileDataToXSSF(file, header);
        }
    }
    /**
     * 读取 Excel文件内容
     *
     * @param file
     * @param header 是否包括表头
     * @return
     * @throws Exception
     */
    public static List<List<String>> readExcelByeFileData(MultipartFile file, boolean header) throws Exception {
        String fileName = file.getOriginalFilename();
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            throw new TipsException("上传文件格式不正确");
        }
        // 结果集
        List<List<String>> list = new ArrayList<>();
        HSSFWorkbook hssfworkbook = new HSSFWorkbook(file.getInputStream());
        // 遍历该表格中所有的工作表,i表示工作表的数量 getNumberOfSheets表示工作表的总数
        for(int s=0;s<hssfworkbook.getNumberOfSheets();s++) {
            HSSFSheet hssfsheet = hssfworkbook.getSheetAt(s);
            int col = 0;
            // 遍历该行所有的行,j表示行数 getPhysicalNumberOfRows行的总数 去除标题
            for (int j = 0; j < hssfsheet.getPhysicalNumberOfRows(); j++) {
                HSSFRow hssfrow = hssfsheet.getRow(j);
                if(hssfrow!=null){
                    if(j == 0) {
                        col = hssfrow.getPhysicalNumberOfCells();
                        if(!header) {
                            //不包括表头
                            continue;
                        }
                    }
                    // 单行数据
                    List<String> arrayString = new ArrayList<>();
                    for (int i = 0; i < col; i++) {
                        HSSFCell cell = hssfrow.getCell(i);
                        if (cell == null) {
                            arrayString.add("");
                        } else if (cell.getCellType() == CellType.NUMERIC) {
                            // arrayString[i] = new Double(cell.getNumericCellValue()).toString();
                            if (CellType.NUMERIC == cell.getCellType()) {
                                short format = cell.getCellStyle().getDataFormat();
                                if(format == 14 || format == 31 || format == 57 || format == 58){
                                    //日期(中文时间格式的)
                                    Date d = cell.getDateCellValue();
                                    DateFormat formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                    // DateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                    arrayString.add(formater.format(d));
                                    //arrayString[i] = formater.format(d);
                                }else if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                    Date d = cell.getDateCellValue();
                                    //DateFormat formater = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
                                    DateFormat formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                    arrayString.add(formater.format(d));
                                    //arrayString[i] = formater.format(d);
                                } else {
                                    if(CellType.STRING == cell.getCellType()){
                                        arrayString.add(cell.getStringCellValue());
                                        //arrayString[i] =cell.getStringCellValue();
                                    }else if(CellType.FORMULA==cell.getCellType()){
                                        arrayString.add(cell.getCellFormula());
                                        //arrayString[i] =cell.getCellFormula();
                                    }else if(CellType.NUMERIC== cell.getCellType()){
                                        HSSFDataFormatter dataFormatter = new HSSFDataFormatter();
                                        arrayString.add(dataFormatter.formatCellValue(cell));
                                        //arrayString[i] =dataFormatter.formatCellValue(cell);
                                    }
                                }
                            }
                        } else if(cell.getCellType() == CellType.BLANK){
                            arrayString.add("");
                            //arrayString[i] = "";
                        } else { // 如果EXCEL表格中的数据类型为字符串型
                            if(cell.getCellType() != CellType.BOOLEAN){
                                arrayString.add(cell.getStringCellValue().trim());
                            }else{
                                arrayString.add(cell.getBooleanCellValue() ? "TRUE" : "FALSE");
                            }
                            //arrayString[i] = cell.getStringCellValue().trim();
                        }
                    }
                    list.add(arrayString);
                }
            }
        }
        return list;
    }
    /**
     * 读取 Excel文件内容
     *
     * @param file
     * @param header 是否包括表头
     * @return
     * @throws Exception
     */
    public static List<List<String>> readExcelByeFileDataToXSSF(MultipartFile file, boolean header) throws Exception {
        String fileName = file.getOriginalFilename();
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            throw new TipsException("上传文件格式不正确");
        }
        // 结果集
        List<List<String>> list = new ArrayList<>();
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file.getInputStream());
        // 遍历该表格中所有的工作表,i表示工作表的数量 getNumberOfSheets表示工作表的总数
        for(int s=0;s<xssfWorkbook.getNumberOfSheets();s++) {
            XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(s);
            int col = 0;
            // 遍历该行所有的行,j表示行数 getPhysicalNumberOfRows行的总数 去除标题
            for (int j = 0; j < xssfSheet.getPhysicalNumberOfRows(); j++) {
                XSSFRow xssfrow = xssfSheet.getRow(j);
                if(xssfrow!=null){
                    if(j == 0) {
                        col = xssfrow.getPhysicalNumberOfCells();
                        if(!header) {
                            //不包括表头
                            continue;
                        }
                    }
                    // 单行数据
                    List<String> arrayString = new ArrayList<>();
                    for (int i = 0; i < col; i++) {
                        XSSFCell cell = xssfrow.getCell(i);
                        if (cell == null) {
                            arrayString.add("");
                        } else if (cell.getCellType() == CellType.NUMERIC) {
                            // arrayString[i] = new Double(cell.getNumericCellValue()).toString();
                            if (CellType.NUMERIC == cell.getCellType()) {
                                short format = cell.getCellStyle().getDataFormat();
                                if(format == 14 || format == 31 || format == 57 || format == 58){
                                    //日期(中文时间格式的)
                                    Date d = cell.getDateCellValue();
                                    DateFormat formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                    // DateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                    arrayString.add(formater.format(d));
                                    //arrayString[i] = formater.format(d);
                                }else if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                    Date d = cell.getDateCellValue();
                                    //DateFormat formater = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
                                    DateFormat formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                    arrayString.add(formater.format(d));
                                    //arrayString[i] = formater.format(d);
                                } else {
                                    if(CellType.STRING == cell.getCellType()){
                                        arrayString.add(cell.getStringCellValue());
                                        //arrayString[i] =cell.getStringCellValue();
                                    }else if(CellType.FORMULA==cell.getCellType()){
                                        arrayString.add(cell.getCellFormula());
                                        //arrayString[i] =cell.getCellFormula();
                                    }else if(CellType.NUMERIC== cell.getCellType()){
                                        HSSFDataFormatter dataFormatter = new HSSFDataFormatter();
                                        arrayString.add(dataFormatter.formatCellValue(cell));
                                        //arrayString[i] =dataFormatter.formatCellValue(cell);
                                    }
                                }
                            }
                        } else if(cell.getCellType() == CellType.BLANK){
                            arrayString.add("");
                            //arrayString[i] = "";
                        } else { // 如果EXCEL表格中的数据类型为字符串型
                            if(cell.getCellType() != CellType.BOOLEAN){
                                arrayString.add(cell.getStringCellValue().trim());
                            }else{
                                arrayString.add(cell.getBooleanCellValue() ? "TRUE" : "FALSE");
                            }
                            //arrayString[i] = cell.getStringCellValue().trim();
                        }
                    }
                    list.add(arrayString);
                }
            }
        }
        return list;
    }
    /**判断excel的版本*/
    public static Workbook create(InputStream inp) throws IOException {
        //这样写  excel 能兼容03和07
        return WorkbookFactory.create(inp);
    }
    /**读取excel文件,兼容2003和2007
     * 通过流读取Excel文件
     * @return
     * @throws Exception
     */
    public static List<List<String>> getExcelDataCompatible(File file,boolean header) throws Exception {
        try {
            String fileName = file.getName();
            if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
                throw new TipsException("上传文件格式不正确");
            }
            // 结果集
            List<List<String>> list = new ArrayList<>();
            Workbook book = create(new BufferedInputStream(new FileInputStream(file)));
            // 遍历该表格中所有的工作表,i表示工作表的数量 getNumberOfSheets表示工作表的总数
            Sheet hssfsheet;
            Row hssfrow;
            List<String> arrayString;
            Cell cell;
            short format;
            Date d;
            DateFormat formater;
            HSSFDataFormatter dataFormatter;
            for(int s=0;s<book.getNumberOfSheets();s++) {
                hssfsheet = book.getSheetAt(s);
                int col = 0;
                // 遍历该行所有的行,j表示行数 getPhysicalNumberOfRows行的总数 去除标题
                for (int j = 0; j < hssfsheet.getPhysicalNumberOfRows(); j++) {
                    hssfrow = hssfsheet.getRow(j);
                    if(hssfrow!=null){
                        if(j == 0) {
                            col = hssfrow.getPhysicalNumberOfCells();
                            if(!header) {
                                //不包括表头
                                continue;
                            }
                        }
                        // 单行数据
                        arrayString = new ArrayList<>();
                        for (int i = 0; i < col; i++) {
                            cell = hssfrow.getCell(i);
                            if (cell == null) {
                                arrayString.add("");
                            } else if (cell.getCellType() == CellType.NUMERIC) {
                                // arrayString[i] = new Double(cell.getNumericCellValue()).toString();
                                if (CellType.NUMERIC == cell.getCellType()) {
                                    format = cell.getCellStyle().getDataFormat();
                                    if(format == 14 || format == 31 || format == 57 || format == 58){
                                        //日期(中文时间格式的)
                                         d = cell.getDateCellValue();
                                         formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                        // DateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                        arrayString.add(formater.format(d));
                                        //arrayString[i] = formater.format(d);
                                    }else if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                        d = cell.getDateCellValue();
                                        //DateFormat formater = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
                                        formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                        arrayString.add(formater.format(d));
                                        //arrayString[i] = formater.format(d);
                                    } else {
                                        if(CellType.STRING == cell.getCellType()){
                                            arrayString.add(cell.getStringCellValue());
                                            //arrayString[i] =cell.getStringCellValue();
                                        }else if(CellType.FORMULA==cell.getCellType()){
                                            arrayString.add(cell.getCellFormula());
                                            //arrayString[i] =cell.getCellFormula();
                                        }else if(CellType.NUMERIC== cell.getCellType()){
                                            dataFormatter = new HSSFDataFormatter();
                                            arrayString.add(dataFormatter.formatCellValue(cell));
                                            //arrayString[i] =dataFormatter.formatCellValue(cell);
                                        }
                                    }
                                }
                            } else if(cell.getCellType() == CellType.BLANK){
                                arrayString.add("");
                                //arrayString[i] = "";
                            } else { // 如果EXCEL表格中的数据类型为字符串型
                                arrayString.add(cell.getStringCellValue().trim());
                                //arrayString[i] = cell.getStringCellValue().trim();
                            }
                        }
                        list.add(arrayString);
                    }
                }
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**读取excel文件,兼容2003和2007
     * 通过流读取Excel文件
     * @return
     * @throws Exception
     */
    public static List<List<String>> getExcelDataCompatible(MultipartFile file,boolean header) throws Exception {
        try {
            String fileName = file.getOriginalFilename();
            if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
                throw new TipsException("上传文件格式不正确");
            }
            // 结果集
            List<List<String>> list = new ArrayList<>();
            Workbook book = create(new BufferedInputStream(file.getInputStream()));
            Sheet hssfsheet;
            Row hssfrow;
            List<String> arrayString;
            Cell cell;
            short format;
            Date d;
            DateFormat formater;
            HSSFDataFormatter dataFormatter;
            // 遍历该表格中所有的工作表,i表示工作表的数量 getNumberOfSheets表示工作表的总数
            for(int s=0;s<book.getNumberOfSheets();s++) {
                hssfsheet = book.getSheetAt(s);
                int col = 0;
                // 遍历该行所有的行,j表示行数 getPhysicalNumberOfRows行的总数 去除标题
                for (int j = 0; j < hssfsheet.getPhysicalNumberOfRows(); j++) {
                    hssfrow = hssfsheet.getRow(j);
                    if(hssfrow!=null){
                        if(j == 0) {
                            col = hssfrow.getPhysicalNumberOfCells();
                            if(!header) {
                                //不包括表头
                                continue;
                            }
                        }
                        // 单行数据
                        arrayString = new ArrayList<>();
                        for (int i = 0; i < col; i++) {
                            cell = hssfrow.getCell(i);
                            if (cell == null) {
                                arrayString.add("");
                            } else if (cell.getCellType() == CellType.NUMERIC) {
                                // arrayString[i] = new Double(cell.getNumericCellValue()).toString();
                                if (CellType.NUMERIC == cell.getCellType()) {
                                    format = cell.getCellStyle().getDataFormat();
                                    if(format == 14 || format == 31 || format == 57 || format == 58){
                                        //日期(中文时间格式的)
                                        d = cell.getDateCellValue();
                                        formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                        // DateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                        arrayString.add(formater.format(d));
                                        //arrayString[i] = formater.format(d);
                                    }else if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                        d = cell.getDateCellValue();
                                        //DateFormat formater = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
                                        formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                        arrayString.add(formater.format(d));
                                        //arrayString[i] = formater.format(d);
                                    } else {
                                        if(CellType.STRING == cell.getCellType()){
                                            arrayString.add(cell.getStringCellValue());
                                            //arrayString[i] =cell.getStringCellValue();
                                        }else if(CellType.FORMULA==cell.getCellType()){
                                            arrayString.add(cell.getCellFormula());
                                            //arrayString[i] =cell.getCellFormula();
                                        }else if(CellType.NUMERIC== cell.getCellType()){
                                            dataFormatter = new HSSFDataFormatter();
                                            arrayString.add(dataFormatter.formatCellValue(cell));
                                            //arrayString[i] =dataFormatter.formatCellValue(cell);
                                        }
                                    }
                                }
                            } else if(cell.getCellType() == CellType.BLANK){
                                arrayString.add("");
                                //arrayString[i] = "";
                            } else { // 如果EXCEL表格中的数据类型为字符串型
                                arrayString.add(cell.getStringCellValue().trim());
                                //arrayString[i] = cell.getStringCellValue().trim();
                            }
                        }
                        list.add(arrayString);
                    }
                }
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**读取excel文件,兼容2003和2007
     * 通过流读取Excel文件
     * @return
     * @throws Exception
     */
    public static List<List<String>> getExcelDataCompatible(InputStream inputStream,boolean header) throws Exception {
        try {
            // 结果集
            List<List<String>> list = new ArrayList<>();
            Workbook book = create(new BufferedInputStream(inputStream));
            Sheet hssfsheet;
            Row hssfrow;
            List<String> arrayString;
            Cell cell;
            short format;
            Date d;
            DateFormat formater;
            HSSFDataFormatter dataFormatter;
            // 遍历该表格中所有的工作表,i表示工作表的数量 getNumberOfSheets表示工作表的总数
            for(int s=0;s<book.getNumberOfSheets();s++) {
                hssfsheet = book.getSheetAt(s);
                int col = 0;
                // 遍历该行所有的行,j表示行数 getPhysicalNumberOfRows行的总数 去除标题
                for (int j = 0; j < hssfsheet.getPhysicalNumberOfRows(); j++) {
                    hssfrow = hssfsheet.getRow(j);
                    if(hssfrow!=null){
                        if(j == 0) {
                            col = hssfrow.getPhysicalNumberOfCells();
                            if(!header) {
                                //不包括表头
                                continue;
                            }
                        }
                        // 单行数据
                        arrayString = new ArrayList<>();
                        for (int i = 0; i < col; i++) {
                            cell = hssfrow.getCell(i);
                            if (cell == null) {
                                arrayString.add("");
                            } else if (cell.getCellType() == CellType.NUMERIC) {
                                // arrayString[i] = new Double(cell.getNumericCellValue()).toString();
                                if (CellType.NUMERIC == cell.getCellType()) {
                                    format = cell.getCellStyle().getDataFormat();
                                    if(format == 14 || format == 31 || format == 57 || format == 58){
                                        //日期(中文时间格式的)
                                        d = cell.getDateCellValue();
                                        formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                        // DateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                        arrayString.add(formater.format(d));
                                        //arrayString[i] = formater.format(d);
                                    }else if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                        d = cell.getDateCellValue();
                                        //DateFormat formater = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
                                        formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                        arrayString.add(formater.format(d));
                                        //arrayString[i] = formater.format(d);
                                    } else {
                                        if(CellType.STRING == cell.getCellType()){
                                            arrayString.add(cell.getStringCellValue());
                                            //arrayString[i] =cell.getStringCellValue();
                                        }else if(CellType.FORMULA==cell.getCellType()){
                                            arrayString.add(cell.getCellFormula());
                                            //arrayString[i] =cell.getCellFormula();
                                        }else if(CellType.NUMERIC== cell.getCellType()){
                                            dataFormatter = new HSSFDataFormatter();
                                            arrayString.add(dataFormatter.formatCellValue(cell));
                                            //arrayString[i] =dataFormatter.formatCellValue(cell);
                                        }
                                    }
                                }
                            } else if(cell.getCellType() == CellType.BLANK){
                                arrayString.add("");
                                //arrayString[i] = "";
                            } else { // 如果EXCEL表格中的数据类型为字符串型
                                arrayString.add(cell.getStringCellValue().trim());
                                //arrayString[i] = cell.getStringCellValue().trim();
                            }
                        }
                        list.add(arrayString);
                    }
                }
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 新版读取Excel,只支持2007以上版本,也就是xslx格式
     * 支持大数据量
     * @param file 文件
     * @return 数据
     */
    public static List<List<String>> readExcelData(File file){
        if(!isExcel(file)){
            throw new TipsException("请上传excel的文件格式!");
        }
        List<List<String>> listData = new ArrayList<>();
        try{
            //rowCacheSize 缓存到内存中的行数(默认是10)
            //bufferSize 读取资源时,缓存到内存的字节大小(默认是1024)
            //open InputStream或者XLSX格式的File(必须)
            Workbook book = StreamingReader.builder()
                    .rowCacheSize(100)
                    .bufferSize(10240)
                    .open(new FileInputStream(file));
            listData =readhandle(book);
        }catch (OLE2NotOfficeXmlFileException ex){
            ex.printStackTrace();
            throw new RuntimeException("excel版本不为2007及以上");
        } catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
        return listData;
    }
    /**
     * 新版读取Excel,只支持2007以上版本,也就是xslx格式
     * 支持大数据量
     * @param file 文件
     * @return 数据
     */
    public static List<List<String>> readExcelData(MultipartFile file){
        if(!isExcel(file)){
            throw new TipsException("请上传excel的文件格式!");
        }
        List<List<String>> listData = new ArrayList<>();
        try{
            //rowCacheSize 缓存到内存中的行数(默认是10)
            //bufferSize 读取资源时,缓存到内存的字节大小(默认是1024)
            //open InputStream或者XLSX格式的File(必须)
            Workbook book = StreamingReader.builder()
                    .rowCacheSize(100)
                    .bufferSize(10240)
                    .open(new BufferedInputStream(file.getInputStream()));
            listData =readhandle(book);
        }catch (OLE2NotOfficeXmlFileException ex){
            ex.printStackTrace();
            throw new RuntimeException("excel版本不为2007及以上");
        } catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
        return listData;
    }
    /**
     * 新版读取Excel,只支持2007以上版本,也就是xslx格式
     * 支持大数据量
     * @param file 文件
     * @return 数据
     */
    public static List<List<String>> readExcelData(InputStream file){
        List<List<String>> listData = new ArrayList<>();
        try{
            //rowCacheSize 缓存到内存中的行数(默认是10)
            //bufferSize 读取资源时,缓存到内存的字节大小(默认是1024)
            //open InputStream或者XLSX格式的File(必须)
            Workbook book = StreamingReader.builder()
                    .rowCacheSize(100)
                    .bufferSize(10240)
                    .open(file);
            listData =readhandle(book);
        }catch (OLE2NotOfficeXmlFileException ex){
            ex.printStackTrace();
            throw new RuntimeException("excel版本不为2007及以上");
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
        return listData;
    }
    /**处理数据*/
    public static List<List<String>> readhandle(Workbook book){
        List<List<String>> listData = new ArrayList<>();
        //是否存在数据
        boolean isData;
        List<String> arrayString;
        short format;
        Date d;
        DateFormat formater;
        Sheet sheet;
        Cell cell;
        //遍历所有的sheet
        for(int i=0;i<book.getNumberOfSheets();i++) {
            sheet = book.getSheetAt(i);
            //列数
            Integer arrange = null;
            //遍历所有的行
            for (Row row : sheet) {
                if(row == null){
                    continue;
                }
                isData = false;
                arrayString = new ArrayList<>();
                if(arrange == null){
                    arrange = row.getPhysicalNumberOfCells();
                }
                //遍历所有的列
                for (int j = 0;j<arrange;j++) {
                    cell = row.getCell(j);
                    if (cell == null) {
                        arrayString.add("");
                    }else{
                        if (cell.getCellType() == CellType.NUMERIC) {
                            isData = true;
                            format = cell.getCellStyle().getDataFormat();
                            if (format == 14 || format == 31 || format == 57 || format == 58) {
                                //日期(中文时间格式的)
                                d = cell.getDateCellValue();
                                formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                arrayString.add(formater.format(d));
                            } else if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                d = cell.getDateCellValue();
                                formater = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                arrayString.add(formater.format(d));
                            } else {
                                if (CellType.STRING == cell.getCellType()) {
                                    arrayString.add(cell.getStringCellValue());
                                } else if (CellType.FORMULA == cell.getCellType()) {
                                    arrayString.add(cell.getCellFormula());
                                } else {
                                    arrayString.add(cell.getStringCellValue().trim());
                                }
                            }
                        } else if (cell.getCellType() == CellType.BLANK) {
                            arrayString.add("");
                        } else { // 如果EXCEL表格中的数据类型为字符串型
                            isData = true;
                            arrayString.add(cell.getStringCellValue().trim());
                        }
                    }
                }
                if (isData) {
                    listData.add(arrayString);
                }
            }
        }
        return listData;
    }
    /**
     * p判断是否excel文件
     * @param file
     * @return
     */
    public static boolean isExcel(MultipartFile file){
        return isExcel(file.getOriginalFilename());
    }
    /**
     * p判断是否excel文件
     * @param file
     * @return
     */
    public static boolean isExcel(File file){
        return isExcel(file.getName());
    }
    /**判断文件格式是不是excel*/
    public static boolean isExcel(String fileName){
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            return false;
        }
        return true;
    }
    public static File createExcelByImg(String[] headList, String[] fieldList, List<Map<String, Object>> dataList, Integer height, Integer width) throws Exception {
        File file = File.createTempFile("temp", ".xls");
        FileOutputStream fileOut = null;
        BufferedImage bufferImg = null;
        try {
            ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
            if (height == null) {
                height = 450;
            }
            if (width == null) {
                width = 1000;
            }
            HSSFWorkbook workbook = new HSSFWorkbook();
            HSSFCellStyle boderStyle = workbook.createCellStyle();
            boderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            boderStyle.setAlignment(HorizontalAlignment.CENTER);
            HSSFSheet sheet = workbook.createSheet();
            HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
            HSSFRow row = sheet.createRow(0);
            HSSFCell anchor;
            for(int i = 0; i < headList.length; ++i) {
                row.setHeight(height.shortValue());
                sheet.setColumnWidth(i, width);
                anchor = row.createCell(i);
                anchor.setCellValue(headList[i]);
                anchor.setCellStyle(boderStyle);
            }
            HSSFRow row_value = null;
            anchor = null;
            HSSFCell cell = null;
            if (dataList != null) {
                for(int n = 0; n < dataList.size(); ++n) {
                    row_value = sheet.createRow(n + 1);
                    row_value.setHeight(height.shortValue());
                    Map<String, Object> dataMap = (Map)dataList.get(n);
                    for(int i = 0; i < fieldList.length; ++i) {
                        sheet.setColumnWidth(i, width);
                        cell = row_value.createCell(i);
                        Object value = dataMap.get(fieldList[i]);
                        if (value != null && "class java.io.File".equals(value.getClass().toString())) {
                            File file2 = (File)value;
                            if (file2 == null) {
                                cell.setCellValue("");
                            } else {
                                bufferImg = ImageIO.read(file2);
                                ImageIO.write(bufferImg, "jpg", byteArrayOut);
                                HSSFClientAnchor anchor1 = new HSSFClientAnchor(0, 0, 1023, 255, (short)i, n + 1, (short)i, n + 1);
                                anchor1.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
                                patriarch.createPicture(anchor1, workbook.addPicture(byteArrayOut.toByteArray(), 5));
                            }
                        } else {
                            cell.setCellValue(objToString(dataMap.get(fieldList[i])));
                            cell.setCellStyle(boderStyle);
                        }
                    }
                }
            }
            FileOutputStream fOut = new FileOutputStream(file);
            workbook.write(fOut);
            fOut.flush();
            fOut.close();
        } catch (Exception var25) {
            var25.printStackTrace();
        } finally {
            file.deleteOnExit();
        }
        return file;
    }
}
hx_common/src/main/java/com/hx/util/FileConvertTool.java
New file
@@ -0,0 +1,351 @@
package com.hx.util;
import com.hx.exception.TipsException;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.IOUtils;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.Base64;
/**
 * 文件转换工具类
 * @USER: fhx
 * @DATE: 2022/3/2
 **/
public class FileConvertTool {
    private static final int  BUFFER_SIZE = 2 * 1024;
    /** 获取网络路径文件流 */
    public static InputStream getUrlFile(String urlPath) throws IOException {
        if(StringUtils.isEmpty(urlPath)){
            return null;
        }
        // 构造URL
        URL url = new URL(urlPath);
        // 打开连接
        URLConnection con = url.openConnection();
        //设置请求超时为5s
        con.setConnectTimeout(5*1000);
        // 输入流
        InputStream is = con.getInputStream();
        return is;
    }
    /**
     * 获取文件base64字符串
     * @param urlPath  文件路径
     * @return 返回base64编码
     */
    public static String getFileBaseStrByUrl(String urlPath) throws IOException {
        InputStream is = getUrlFile(urlPath);
        byte[] bytes = IOUtils.toByteArray(is);
        String encoded = Base64.getEncoder().encodeToString(bytes);
        return encoded;
    }
    // inputStream转outputStream
    public static ByteArrayOutputStream parse(final InputStream in) throws Exception {
        final ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        int ch;
        while ((ch = in.read()) != -1) {
            swapStream.write(ch);
        }
        return swapStream;
    }
    // outputStream转inputStream
    public static ByteArrayInputStream parse(final OutputStream out) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos = (ByteArrayOutputStream) out;
        final ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
        return swapStream;
    }
    // inputStream转String
    public static String parse_String(final InputStream in) throws Exception {
        final ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        int ch;
        while ((ch = in.read()) != -1) {
            swapStream.write(ch);
        }
        return swapStream.toString();
    }
    // OutputStream 转String
    public static String parse_String(final OutputStream out) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos = (ByteArrayOutputStream) out;
        final ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
        return swapStream.toString();
    }
    // String转inputStream
    public static ByteArrayInputStream parse_inputStream(final String in) throws Exception {
        final ByteArrayInputStream input = new ByteArrayInputStream(in.getBytes());
        return input;
    }
    // String 转outputStream
    public static ByteArrayOutputStream parse_outputStream(final String in) throws Exception {
        return parse(parse_inputStream(in));
    }
    /**
     * 根据byte数组,生成文件
     */
    public static File getFile(byte[] bfile, String filePath,String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            File dir = new File(filePath);
            if(!dir.exists()){//判断文件目录是否存在
                dir.mkdirs();
            }
            file = new File(filePath+"/"+fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        return file;
    }
    /**
     * 根据byte数组,生成文件
     */
    public static File getFile(InputStream in, String filePath, String fileName) {
        if(in == null){
            return null;
        }
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            File dir = new File(filePath);
            //判断文件目录是否存在
            if(!dir.exists()){
                dir.mkdirs();
            }
            file = new File(filePath+"/"+fileName);
            fos = new FileOutputStream(file);
            byte[] b = new byte[BUFFER_SIZE];
//            while ((in.read(b)) != -1) {
//                fos.write(b); // 写入数据
//            }
            int len;
            while ((len = in.read(b)) != -1){
                fos.write(b, 0, len);
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        return file;
    }
    /**
     * 获得指定文件的byte数组
     */
    private static byte[] getBytes(String filePath){
        byte[] buffer = null;
        try {
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;
    }
    public static MultipartFile getMultipartFile(File file) {
        FileItem item = new DiskFileItemFactory().createItem("file"
                , MediaType.MULTIPART_FORM_DATA_VALUE
                , true
                , file.getName());
        try (InputStream input = new FileInputStream(file);
             OutputStream os = item.getOutputStream()) {
            // 流转移
            IOUtils.copy(input, os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        }
        return new CommonsMultipartFile(item);
    }
    /**
     *  根据路径删除指定的目录或文件,无论存在与否
     *@param sPath  要删除的目录或文件
     *@return 删除成功返回 true,否则返回 false。
     */
    public static boolean deleteFolder(String sPath) {
        File file = new File(sPath);
        // 判断目录或文件是否存在
        if (!file.exists()) {
            // 不存在返回 true
            return true;
        } else {
            // 判断是否为文件
            if (file.isFile()) {  // 为文件时调用删除文件方法
                return deleteFile(sPath);
            } else {  // 为目录时调用删除目录方法
                return deleteDirectory(sPath);
            }
        }
    }
    /**
     * 删除单个文件
     * @param   sPath    被删除文件的文件名
     * @return 单个文件删除成功返回true,否则返回false
     */
    public static boolean deleteFile(String sPath) {
        File  file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            return true;
        }
        return false;
    }
    /**
     * 删除单个文件
     * @param   file    被删除文件
     * @return 单个文件删除成功返回true,否则返回false
     */
    public static boolean deleteFile(File file) {
        if(file == null){
            return true;
        }
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            return true;
        }
        return false;
    }
    /**
     * 删除目录(文件夹)以及目录下的文件
     * @param   sPath 被删除目录的文件路径
     * @return  目录删除成功返回true,否则返回false
     */
    public static boolean deleteDirectory(String sPath) {
        //如果sPath不以文件分隔符结尾,自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        //如果dir对应的文件不存在,或者不是一个目录,则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            //删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag) break;
            } //删除子目录
            else {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) break;
            }
        }
        if (!flag) return false;
        //删除当前目录
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }
    public static String encodeBase64File(File file) throws Exception {
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] bytes = new byte[fileInputStream.available()];
        // 读取到 byte 里面
        fileInputStream.read(bytes);
        fileInputStream.close();
        BASE64Encoder base64Encoder = new BASE64Encoder();
        // 得到文件 之后转成beye 然后使用base64转码
        // 转码
        String encode = base64Encoder.encode(bytes);
         return encode;
    }
    public static String encodeBase64File(MultipartFile multipartFile) throws Exception {
        if (multipartFile == null) {
            throw new TipsException("未检查到上传的文件!");
        }
        String imageBaseStr = null;
        try {
            String contentType = multipartFile.getContentType();
            byte[] imageBytes = multipartFile.getBytes();
            BASE64Encoder base64Encoder = new BASE64Encoder();
//            imageBaseStr = "data:" + contentType + ";base64," + base64Encoder.encode(imageBytes);
            imageBaseStr = base64Encoder.encode(imageBytes);
            imageBaseStr = imageBaseStr.replaceAll("[\\s*\t\n\r]", "");
        } catch (IOException e) {
            throw new TipsException("文件转换base64异常");
        }
        //返回生成的编码
        return imageBaseStr;
    }
}
hx_common/src/main/java/com/hx/util/FileUtil.java
New file
@@ -0,0 +1,94 @@
package com.hx.util;
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.net.URL;
/**
 * 文件读取工具类
 * @author ChenJiaHe
 * @Date 2020-06-17
 */
public class FileUtil {
    /**
     * @param pathUrl 网络路径
     * @return 文件
     */
    public static File getUrlFile(String pathUrl){
        File temp = null;
        try{
            URL url = new URL(pathUrl);
            temp = File.createTempFile("temp", ".xls");
            FileUtils.copyURLToFile(url, temp);
            temp.deleteOnExit();
        }catch (Exception e){
            throw new RuntimeException("通过URL获取文件出错",e);
        }
        return temp;
    }
    /**
     * 读取文件内容,作为字符串返回
     */
    public static String readFileAsString(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException(filePath);
        }
        if (file.length() > 1024 * 1024 * 1024) {
            throw new IOException("File is too large");
        }
        StringBuilder sb = new StringBuilder((int) (file.length()));
        // 创建字节输入流
        FileInputStream fis = new FileInputStream(filePath);
        // 创建一个长度为10240的Buffer
        byte[] bbuf = new byte[10240];
        // 用于保存实际读取的字节数
        int hasRead = 0;
        while ( (hasRead = fis.read(bbuf)) > 0 ) {
            sb.append(new String(bbuf, 0, hasRead));
        }
        fis.close();
        return sb.toString();
    }
    /**
     * 根据文件路径读取byte[] 数组
     */
    public static byte[] readFileByBytes(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException(filePath);
        } else {
            ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
            BufferedInputStream in = null;
            try {
                in = new BufferedInputStream(new FileInputStream(file));
                short bufSize = 1024;
                byte[] buffer = new byte[bufSize];
                int len1;
                while (-1 != (len1 = in.read(buffer, 0, bufSize))) {
                    bos.write(buffer, 0, len1);
                }
                byte[] var7 = bos.toByteArray();
                return var7;
            } finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (IOException var14) {
                    var14.printStackTrace();
                }
                bos.close();
            }
        }
    }
}
hx_common/src/main/java/com/hx/util/FileUtils.java
New file
@@ -0,0 +1,666 @@
package com.hx.util;
import com.hx.exception.TipsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.FileNameMap;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/** 文件处理工具
 * @author ChenJiaHe
 * @Date 2020-06-17
 */
public class FileUtils {
    private final static Logger logger = LoggerFactory.getLogger(FileUtils.class);
    private static int BUFFER_SIZE = 1024;
    /**
     * @param path
     * @MethodName fileIsExists
     * @Description 文件是否存在
     * @Author ChenJiaHe
     * @Date 2019/9/7 9:13
     * @Since JDK 1.8
     */
    public static boolean fileIsExists(String path) {
        File file = new File(path);
        if (file.exists()) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * @param sourceFile
     * @param targetFile
     * @MethodName copyFile
     * @Description 复制文件
     * @Author ChenJiaHe
     * @Date 2019/9/7 9:36
     * @Since JDK 1.8
     */
    public static void copyFile(File sourceFile, File targetFile) throws IOException {
        BufferedInputStream inputStream = null;
        BufferedOutputStream outputStream = null;
        try {
            inputStream = new BufferedInputStream(new FileInputStream(sourceFile));
            outputStream = new BufferedOutputStream(new FileOutputStream(targetFile));
            byte[] b = new byte[BUFFER_SIZE];
            int len;
            while ((len = inputStream.read(b)) != -1) {
                outputStream.write(b, 0, len);
            }
            outputStream.flush();
        } catch (Exception e) {
            logger.error("copy file error", e);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
    /**
     * @param path
     * @param fileType 文件类型,0 = 文件夹 1 = 文件
     * @MethodName getAllFiles
     * @Description 讀取文件夹下的,不包括子文件夹内
     * @Author ChenJiaHe
     * @Date 2019/9/17 15:56
     * @Since JDK 1.8
     */
    public static List<String> getAllFiles(String path, String fileType) {
        List<String> fileList = new ArrayList<>();
        File fileDic = new File(path);
        File[] files = fileDic.listFiles();
        for (File file : files) {
            if ("1".equals(fileType)) {
                if (file.isFile()) {
                    fileList.add(file.toString());
                }
            }
            if ("0".equals(fileType)) {
                if (file.isDirectory()) {
                    fileList.add(file.toString());
                }
            }
        }
        return fileList;
    }
    /**
     * @param path
     * @MethodName getFolderFiles
     * @Description 递归获取所有包括子文件夹的文件
     * @Author ChenJiaHe
     * @Date 2019/9/17 16:11
     * @Since JDK 1.8
     */
    public static void getAllFileName(String path, List<String> listFileName) {
        try {
            File file = new File(path);
            File[] files = file.listFiles();
            String[] names = file.list();
            if (names != null) {
                String[] completNames = new String[names.length];
                for (int i = 0; i < names.length; i++) {
                    completNames[i] = path + names[i];
                }
                listFileName.addAll(Arrays.asList(completNames));
            }
            for (File a : files) {
                // 如果文件夹下有子文件夹,获取子文件夹下的所有文件全路径。
                if (a.isDirectory()) {
                    getAllFileName(a.getAbsolutePath() + "\\", listFileName);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 读取文件内容,作为字符串返回
     */
    public static String readFileAsString(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException(filePath);
        }
        if (file.length() > 1024 * 1024 * 1024) {
            throw new IOException("File is too large");
        }
        StringBuilder sb = new StringBuilder((int) (file.length()));
        // 创建字节输入流
        FileInputStream fis = new FileInputStream(filePath);
        // 创建一个长度为10240的Buffer
        byte[] bbuf = new byte[10240];
        // 用于保存实际读取的字节数
        int hasRead = 0;
        while ( (hasRead = fis.read(bbuf)) > 0 ) {
            sb.append(new String(bbuf, 0, hasRead));
        }
        fis.close();
        return sb.toString();
    }
    /**
     * 根据文件路径读取byte[] 数组
     */
    public static byte[] readFileByBytes(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException(filePath);
        } else {
            ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
            BufferedInputStream in = null;
            try {
                in = new BufferedInputStream(new FileInputStream(file));
                short bufSize = 1024;
                byte[] buffer = new byte[bufSize];
                int len1;
                while (-1 != (len1 = in.read(buffer, 0, bufSize))) {
                    bos.write(buffer, 0, len1);
                }
                byte[] var7 = bos.toByteArray();
                return var7;
            } finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (IOException var14) {
                    var14.printStackTrace();
                }
                bos.close();
            }
        }
    }
    /**
     *  2020-06-29
     *  cjh
     * 图片格式判断
     * */
    public static boolean imageFormatJudge(MultipartFile firs) {
        String imageName = firs.getOriginalFilename();
        //截取格式
        String suffix =imageName.substring(imageName.lastIndexOf(".") + 1);
        //格式字母转小写
        suffix = suffix.toLowerCase();
        //进行判断
        if(suffix.equals("png")) {
            return true;
        }else if(suffix.equals("jpg")){
            return true;
        }else if(suffix.equals("jpeg")){
            return true;
        }else {
            return false;
        }
    }
    /**
     *  2020-06-29
     *  cjh
     * 图片格式判断
     * */
    public static boolean imageFormatJudge(File firs) {
        String imageName = firs.getName();
        //截取格式
        String suffix =imageName.substring(imageName.lastIndexOf(".") + 1);
        //格式字母转小写
        suffix = suffix.toLowerCase();
        //进行判断
        if(suffix.equals("png")) {
            return true;
        }else if(suffix.equals("jpg")){
            return true;
        }else if(suffix.equals("jpeg")){
            return true;
        }else {
            return false;
        }
    }
    /**视频上传的方法
     * 保存到服务器里面的
     * @param platformIconFile 视频文件
     * @param unifiedFolder NG指向的前端文件夹(统一文件夹),如:user/local/images/
     * @param saveFolder 保存到的文件夹,如:/bananer/
     * @param autoDateFolder 是否生成日期文件夹
     * @return 图片路径
     * 2020-06-29 ChenJiaHe
     */
    public static String videoFileUpload(MultipartFile platformIconFile,String unifiedFolder,String saveFolder
            ,boolean autoDateFolder) {
        String fileName = "";
        try {
            if(platformIconFile == null) {
                throw new TipsException("请上传视频文件!");
            }
            if(!getMimeType(platformIconFile.getOriginalFilename())){
                throw new TipsException("请上传视频格式的文件!");
            }
            //设置图片大小
            // String.format("%.1f",platformIconFile.getSize()/1024.0);
            if(autoDateFolder){
                if(saveFolder.endsWith("/")){
                    saveFolder = saveFolder+dateFormat(new Date(),"yyyyMM")+"/";
                }else{
                    saveFolder = saveFolder+"/"+dateFormat(new Date(),"yyyyMM")+"/";
                }
            }
            fileName = dateFormat(new Date(),"yyyyMMddHHmmssSSS");
            if(unifiedFolder.endsWith("/")){
                if(saveFolder.startsWith("/")){
                    saveFolder = saveFolder.replaceFirst("/","");
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+saveFolder;
                }
            }else{
                if(saveFolder.startsWith("/")){
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+"/"+saveFolder;
                }
            }
            fileName = saveFolder+fileUp(platformIconFile,unifiedFolder,fileName);
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
        return fileName;
    }
    /**图片上传的方法
     * 保存到服务器里面的
     * @param platformIconFile 图片文件
     * @param unifiedFolder NG指向的前端文件夹(统一文件夹),如:user/local/images/
     * @param saveFolder 保存到的文件夹,如:/bananer/
     * @param autoDateFolder 是否生成日期文件夹
     * @return 图片路径
     * 2020-06-29 ChenJiaHe
     */
    public static String handleFileUpload(File platformIconFile,String unifiedFolder,String saveFolder
            ,boolean autoDateFolder) {
        String fileName = "";
        try {
            if(platformIconFile == null) {
                throw new TipsException("请上传图片!");
            }
            if(!imageFormatJudge(platformIconFile)) {
                throw new TipsException("请上传png、jpg和jpeg格式的图片!");
            }
            //设置图片大小
            // String.format("%.1f",platformIconFile.getSize()/1024.0);
            if(autoDateFolder){
                if(saveFolder.endsWith("/")){
                    saveFolder = saveFolder+dateFormat(new Date(),"yyyyMM")+"/";
                }else{
                    saveFolder = saveFolder+"/"+dateFormat(new Date(),"yyyyMM")+"/";
                }
            }
            fileName = dateFormat(new Date(),"yyyyMMddHHmmssSSS");
            if(unifiedFolder.endsWith("/")){
                if(saveFolder.startsWith("/")){
                    saveFolder = saveFolder.replaceFirst("/","");
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+saveFolder;
                }
            }else{
                if(saveFolder.startsWith("/")){
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+"/"+saveFolder;
                }
            }
            fileName = saveFolder+fileUp(platformIconFile,unifiedFolder,fileName);
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
        return fileName;
    }
    /**图片上传的方法
     * 保存到服务器里面的
     * @param platformIconFile 图片文件
     * @param unifiedFolder NG指向的前端文件夹(统一文件夹),如:user/local/images/
     * @param saveFolder 保存到的文件夹,如:/bananer/
     * @param autoDateFolder 是否生成日期文件夹
     * @return 图片路径
     * 2020-06-29 ChenJiaHe
     */
    public static String handleFileUpload(MultipartFile platformIconFile,String unifiedFolder,String saveFolder
            ,boolean autoDateFolder) {
        String fileName = "";
        try {
            if(platformIconFile == null) {
                throw new TipsException("请上传图片!");
            }
            if(!imageFormatJudge(platformIconFile)) {
                throw new TipsException("请上传png、jpg和jpeg格式的图片!");
            }
            //设置图片大小
            // String.format("%.1f",platformIconFile.getSize()/1024.0);
            if(autoDateFolder){
                if(saveFolder.endsWith("/")){
                    saveFolder = saveFolder+dateFormat(new Date(),"yyyyMM")+"/";
                }else{
                    saveFolder = saveFolder+"/"+dateFormat(new Date(),"yyyyMM")+"/";
                }
            }
            fileName = dateFormat(new Date(),"yyyyMMddHHmmssSSS");
            if(unifiedFolder.endsWith("/")){
                if(saveFolder.startsWith("/")){
                    saveFolder = saveFolder.replaceFirst("/","");
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+saveFolder;
                }
            }else{
                if(saveFolder.startsWith("/")){
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+"/"+saveFolder;
                }
            }
            fileName = saveFolder+fileUp(platformIconFile,unifiedFolder,fileName);
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
        return fileName;
    }
    /**
     * 音频上传
     * @param platformIconFile
     * @param unifiedFolder
     * @param saveFolder
     * @param autoDateFolder
     * @return
     */
    public static String handleAudioUpload(MultipartFile platformIconFile,String unifiedFolder,String saveFolder
            ,boolean autoDateFolder) {
        String fileName = "";
        try {
            if(platformIconFile == null) {
                throw new TipsException("请上传音频!");
            }
            if(autoDateFolder){
                if(saveFolder.endsWith("/")){
                    saveFolder = saveFolder+dateFormat(new Date(),"yyyyMM")+"/";
                }else{
                    saveFolder = saveFolder+"/"+dateFormat(new Date(),"yyyyMM")+"/";
                }
            }
            fileName = dateFormat(new Date(),"yyyyMMddHHmmssSSS");
            if(unifiedFolder.endsWith("/")){
                if(saveFolder.startsWith("/")){
                    saveFolder = saveFolder.replaceFirst("/","");
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+saveFolder;
                }
            }else{
                if(saveFolder.startsWith("/")){
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+"/"+saveFolder;
                }
            }
            fileName = saveFolder+fileUp(platformIconFile,unifiedFolder,fileName);
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
        return fileName;
    }
    /**
     * 文件上传
     * @param platformIconFile
     * @param unifiedFolder
     * @param saveFolder
     * @param autoDateFolder
     * @return
     */
    public static String handleOtherFileUpload(MultipartFile platformIconFile,String unifiedFolder,String saveFolder
            ,boolean autoDateFolder) {
        String fileName = "";
        try {
            if(platformIconFile == null) {
                throw new TipsException("请上传文件!");
            }
            if(autoDateFolder){
                if(saveFolder.endsWith("/")){
                    saveFolder = saveFolder+dateFormat(new Date(),"yyyyMM")+"/";
                }else{
                    saveFolder = saveFolder+"/"+dateFormat(new Date(),"yyyyMM")+"/";
                }
            }
            fileName = dateFormat(new Date(),"yyyyMMddHHmmssSSS");
            if(unifiedFolder.endsWith("/")){
                if(saveFolder.startsWith("/")){
                    saveFolder = saveFolder.replaceFirst("/","");
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+saveFolder;
                }
            }else{
                if(saveFolder.startsWith("/")){
                    unifiedFolder  = unifiedFolder + saveFolder;
                }else{
                    unifiedFolder  = unifiedFolder+"/"+saveFolder;
                }
            }
            fileName = saveFolder+fileUp(platformIconFile,unifiedFolder,fileName);
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
        return fileName;
    }
    /**
     * 2020-06-29 ChenJiaHe
          * @param file             //文件对象
          * @param filePath        //上传路径
          * @param fileName        //文件名
          * @return  文件名
          */
    public static String fileUp(MultipartFile file, String filePath, String fileName){
        String extName = ""; // 扩展名格式:
        try {
            if (file.getOriginalFilename().lastIndexOf(".") >= 0){
                extName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
            }
            copyFile(file.getInputStream(), filePath, fileName+extName).replaceAll("-", "");
        } catch (IOException e) {
            System.out.println(e);
        }
        return fileName+extName;
    }
    /**
     * 2020-06-29 ChenJiaHe
          * @param file             //文件对象
          * @param filePath        //上传路径
          * @param fileName        //文件名
          * @return  文件名
          */
    public static String fileUp(File file, String filePath, String fileName){
        String extName = ""; // 扩展名格式:
        try {
            if (file.getName().lastIndexOf(".") >= 0){
                extName = file.getName().substring(file.getName().lastIndexOf("."));
            }
            copyFile(file, filePath, fileName+extName).replaceAll("-", "");
        } catch (IOException e) {
            System.out.println(e);
        }
        return fileName+extName;
    }
    /**
      * 写文件到当前目录的upload目录中
      *
      * @param in
      * @param fileName
      * @throws IOException
      */
    private static String copyFile(InputStream in, String dir, String realName)throws IOException {
        File file = new File(dir, realName);
        file.setWritable(true);
        if (!file.exists()) {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            file.createNewFile();
        }
        org.apache.commons.io.FileUtils.copyInputStreamToFile(in, file);
        return realName;
    }
    /**
          * 写文件到当前目录的upload目录中
          *
          * @param in
          * @param fileName
          * @throws IOException
          */
    private static String copyFile(File fileIn, String dir, String realName)throws IOException {
        File file = new File(dir, realName);
        file.setWritable(true);
        if (!file.exists()) {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            file.createNewFile();
        }
        org.apache.commons.io.FileUtils.copyFile(fileIn,file);
        return realName;
    }
    /**
     *
     * @param date 时间
     * @param format 时间格式
     * @return 返回的时间格式字符串
     */
    public static String dateFormat(Date  date,String format) {
        SimpleDateFormat df = new SimpleDateFormat(format);//设置日期格式
        return df.format(date);
    }
    /**
     * @param stream 文件流
     * @param saveUrl 保存到的文件夹
     * @param fileName 文件图片
     * @return
     * @throws IOException
     */
    public static File inputStreamToFile(InputStream stream,String saveUrl,String fileName) throws IOException {
        if(saveUrl.endsWith("/")){
            saveUrl = saveUrl + fileName;
        }else{
            saveUrl = saveUrl +"/"+ fileName;
        }
        File targetFile = new File(saveUrl);
        org.apache.commons.io.FileUtils.copyInputStreamToFile(stream, targetFile);
        return targetFile;
    }
    /**判断是不是视频文件
     * @param fileName 文件名称
     * @return boolean true是视频文件
     */
    public static boolean getMimeType(String fileName) {
        boolean b = false;
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String type = fileNameMap.getContentTypeFor(fileName);
        //是视频type是为空的
        if(StringUtils.isEmpty(type)) {
            b = true;
        }
        return b;
    }
    /**
     * 判断是否为视频
     * @param fileName
     * @return
     */
    public static String isVideo(String fileName) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String type = fileNameMap.getContentTypeFor(fileName);
        return type;
    }
    public static File httpUrlFile(String netUrl) throws IOException {
        File file = File.createTempFile("temp123", ".xls");
        InputStream inStream = null;
        FileOutputStream os = null;
        try {
            file = File.createTempFile("net_url", ".jpg");
            URL urlfile = new URL(netUrl);
            inStream = urlfile.openStream();
            os = new FileOutputStream(file);
            byte[] buffer = new byte[8192];
            int bytesRead;
            while((bytesRead = inStream.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (Exception var15) {
            var15.printStackTrace();
        } finally {
            try {
                if (null != os) {
                    os.close();
                }
                if (null != inStream) {
                    inStream.close();
                }
            } catch (Exception var14) {
                var14.printStackTrace();
            }
        }
        return file;
    }
}
hx_common/src/main/java/com/hx/util/GsonUtils.java
New file
@@ -0,0 +1,29 @@
/*
 * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
 */
package com.hx.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
/**
 * Json工具类.
 */
public class GsonUtils {
    private static Gson gson = new GsonBuilder().create();
    public static String toJson(Object value) {
        return gson.toJson(value);
    }
    public static <T> T fromJson(String json, Class<T> classOfT) throws JsonParseException {
        return gson.fromJson(json, classOfT);
    }
    public static <T> T fromJson(String json, Type typeOfT) throws JsonParseException {
        return (T) gson.fromJson(json, typeOfT);
    }
}
hx_common/src/main/java/com/hx/util/HttpMethodUtil.java
New file
@@ -0,0 +1,151 @@
package com.hx.util;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
 * http 工具类
 */
public class HttpMethodUtil {
    /** 请求http协议 获取信息工具
     * @param url 请求链接
     * @param data 请求数据(body)
     * @param keyValues form表单数据 key参数名称,value参数值
     * @param header 请求头
     * @param requestMethod 请求头方法,默认POST
     * @return
     */
    public static String HttpURLUtilJson(String url, String data,Map<String,Object> keyValues,Map<String,String> header,String requestMethod) {
        HttpURLConnection con = null;
        URL u = null;
        String wxMsgXml = null;
        try {
            StringBuilder dataP = new StringBuilder();
            if (keyValues != null && !keyValues.isEmpty()) {
                for (Map.Entry<String, Object> entry : keyValues.entrySet()) {
                    dataP.append((String)entry.getKey()).append("=");
                    dataP.append(entry.getValue());
                    dataP.append("&");
                }
                System.out.println("dataP:"+dataP.toString());
                dataP.deleteCharAt(dataP.length() - 1);
                url = url+"?"+dataP;
            }
            if(StringUtils.isEmpty(requestMethod)){
                requestMethod = "POST";
            }
            u = new URL(url);
            con = (HttpURLConnection) u.openConnection();
            con.setRequestMethod(requestMethod);
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setReadTimeout(300000);
            con.setRequestProperty("Charset", "UTF-8");
            con.setRequestProperty("Content-Type", "application/json");
            if(header != null){
                for (Map.Entry<String, String> entry : header.entrySet()) {
                    con.setRequestProperty(entry.getKey(),entry.getValue());
                }
            }
            if (data != null) {
                OutputStream os = con.getOutputStream();
                os.write(data.getBytes("utf-8"));
            }
            if(HttpURLConnection.HTTP_OK != con.getResponseCode() && HttpURLConnection.HTTP_CREATED != con.getResponseCode()){
                throw new RuntimeException("请求url失败:"+con.getResponseCode());
            }
            // 读取返回内容
            wxMsgXml = IOUtils.toString(con.getInputStream(), "utf-8");
            // //System.out.println("HttpURLUtil:"+wxMsgXml);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        return wxMsgXml;
    }
    /**
     * 请求http协议 获取信息工具
     * @param url 请求链接
     * @param data 请求数据(body)
     * @param keyValues form表单数据 key参数名称,value参数值
     * @param header 请求头
     * @param requestMethod 请求头方法,默认POST
     * @return
     */
    public static String request(String url, String data,Map<String,Object> keyValues,Map<String,String> header,String requestMethod, String contentType) {
        HttpURLConnection con = null;
        URL u = null;
        String wxMsgXml = null;
        try {
            StringBuilder dataP = new StringBuilder();
            if (keyValues != null && !keyValues.isEmpty()) {
                for (Map.Entry<String, Object> entry : keyValues.entrySet()) {
                    dataP.append((String)entry.getKey()).append("=");
                    dataP.append(entry.getValue());
                    dataP.append("&");
                }
                System.out.println("dataP:"+dataP.toString());
                dataP.deleteCharAt(dataP.length() - 1);
                url = url+"?"+dataP;
            }
            if(StringUtils.isEmpty(requestMethod)){
                requestMethod = "POST";
            }
            if(StringUtils.isEmpty(contentType)){
                contentType = "application/json";
            }
            u = new URL(url);
            con = (HttpURLConnection) u.openConnection();
            con.setRequestMethod(requestMethod);
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setReadTimeout(300000);
            con.setRequestProperty("Charset", "UTF-8");
            con.setRequestProperty("Content-Type", contentType);
            if(header != null){
                for (Map.Entry<String, String> entry : header.entrySet()) {
                    con.setRequestProperty(entry.getKey(),entry.getValue());
                }
            }
            if (data != null) {
                OutputStream os = con.getOutputStream();
                os.write(data.getBytes("utf-8"));
            }
            if(HttpURLConnection.HTTP_OK != con.getResponseCode() && HttpURLConnection.HTTP_CREATED != con.getResponseCode()){
                throw new RuntimeException("请求url失败:"+con.getResponseCode());
            }
            // 读取返回内容
            wxMsgXml = IOUtils.toString(con.getInputStream(), "utf-8");
            // //System.out.println("HttpURLUtil:"+wxMsgXml);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        return wxMsgXml;
    }
}
hx_common/src/main/java/com/hx/util/HttpResponse.java
New file
@@ -0,0 +1,32 @@
package com.hx.util;
public class HttpResponse {
    private int code;
    private String content;
    public HttpResponse(int status, String content) {
        this.code = status;
        this.content = content;
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String toString(){
        return new StringBuilder("[ code = ").append(code)
                .append(" , content = ").append(content).append(" ]").toString();
    }
}
hx_common/src/main/java/com/hx/util/HttpServletRequestUtil.java
New file
@@ -0,0 +1,53 @@
package com.hx.util;
import org.apache.commons.io.IOUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/** HttpServletRequestUtil  获取请求中的body
 * @author wangrenhuang
 * @Date 2021-10-19
 */
public class HttpServletRequestUtil {
    /**
    * 获取bady
    * */
    public static String getBody(HttpServletRequest request) {
        String wxMsgXml = null;
        if(request == null){
            return wxMsgXml;
        }
        try{
            wxMsgXml = IOUtils.toString(request.getInputStream(),
                    "utf-8");
            return wxMsgXml;
        }catch (Exception e){
            wxMsgXml = null;
        }
        return wxMsgXml;
    }
    /**
    *
    * 获取请求头
    * */
    public static Map<String,String> getHeader(HttpServletRequest request) {
        Enumeration<String> enumeration = request.getHeaderNames();
        Map<String,String> map = new HashMap<>(16);
        StringBuffer headers = new StringBuffer();
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement();
            String value = request.getHeader(name);
            map.put(name,value);
        }
        return map;
    }
}
Diff truncated after the above file
hx_common/src/main/java/com/hx/util/HttpUtil.java hx_common/src/main/java/com/hx/util/IPUtils.java hx_common/src/main/java/com/hx/util/ImageBase64Util.java hx_common/src/main/java/com/hx/util/ImagesAddDomain.java hx_common/src/main/java/com/hx/util/JwtConstant.java hx_common/src/main/java/com/hx/util/JwtTool.java hx_common/src/main/java/com/hx/util/MD5.java hx_common/src/main/java/com/hx/util/MD5Util.java hx_common/src/main/java/com/hx/util/MapUtil.java hx_common/src/main/java/com/hx/util/MultipartFileUtil.java hx_common/src/main/java/com/hx/util/MyRedisTemplate.java hx_common/src/main/java/com/hx/util/NumberUtil.java hx_common/src/main/java/com/hx/util/OBSUtil.java hx_common/src/main/java/com/hx/util/OSSUtil.java hx_common/src/main/java/com/hx/util/QRCodeUtil.java hx_common/src/main/java/com/hx/util/RegValidatorUtil.java hx_common/src/main/java/com/hx/util/RequestMethod.java hx_common/src/main/java/com/hx/util/SerializeUtil.java hx_common/src/main/java/com/hx/util/SimpleEncrypt.java hx_common/src/main/java/com/hx/util/SimpleTool.java hx_common/src/main/java/com/hx/util/StreamUtils.java hx_common/src/main/java/com/hx/util/StringUtils.java hx_common/src/main/java/com/hx/util/TempltUtil.java hx_common/src/main/java/com/hx/util/TengXunMapUtil.java hx_common/src/main/java/com/hx/util/ThreadPoolUtils.java hx_common/src/main/java/com/hx/util/WebUtil.java hx_common/src/main/java/com/hx/util/XmlUtil.java hx_common/src/main/java/com/hx/util/code/NumberTool.java hx_common/src/main/java/com/hx/util/corp/CorpMpUtil.java hx_common/src/main/java/com/hx/util/corp/entity/AppLetInfo.java hx_common/src/main/java/com/hx/util/corp/entity/OpenIdAUserId.java hx_common/src/main/java/com/hx/util/corp/entity/WeiXinInfo.java hx_common/src/main/java/com/hx/util/gaode/AddressCode.java hx_common/src/main/java/com/hx/util/gaode/GaoDeMapUtil.java hx_common/src/main/java/com/hx/util/mysql/aes/MysqlHexAesTool.java hx_common/src/main/java/com/hx/util/rsa/Base64.java hx_common/src/main/java/com/hx/util/rsa/RSASignature.java hx_common/src/main/java/com/hx/util/rsa/RSAUtil.java hx_common/src/main/java/com/hx/util/thread/ExecutorServiceTool.java hx_common/src/main/java/com/hx/wx/gzh/WxGzhUtil.java hx_common/src/main/java/com/hz/util/http/HttpHzUtil.java hx_common/src/main/java/com/hz/util/http/dto/HttpHzResponse.java hx_common/src/main/java/com/qq/weixin/mp/aes/AesException.java hx_common/src/main/java/com/qq/weixin/mp/aes/ByteGroup.java hx_common/src/main/java/com/qq/weixin/mp/aes/PKCS7Encoder.java hx_common/src/main/java/com/qq/weixin/mp/aes/SHA1.java hx_common/src/main/java/com/qq/weixin/mp/aes/WXBizMsgCrypt.java hx_common/src/main/java/com/qq/weixin/mp/aes/XMLParse.java pom.xml