main
commit
ce521f309a
|
|
@ -0,0 +1,8 @@
|
|||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="edu_videoresource" />
|
||||
<module name="shopping-mall" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="edu_videoresource" options="-parameters" />
|
||||
<module name="shopping-mall" options="-parameters" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="@192.168.0.18" uuid="01a2ee37-9482-4c10-9f75-9754f97d2f62">
|
||||
<driver-ref>mysql.8</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:mysql://192.168.0.18:33061</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,631 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EasyCodeTableSetting">
|
||||
<option name="tableInfoMap">
|
||||
<map>
|
||||
<entry key="videoresource.bus_chapter_copy1">
|
||||
<value>
|
||||
<TableInfoDTO>
|
||||
<option name="comment" value="没用" />
|
||||
<option name="fullColumn">
|
||||
<list>
|
||||
<ColumnInfoDTO>
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="chapterId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="章节名字" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="name" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="添加人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="creator" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="添加时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="createTime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="修改人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="operator" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="修改时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="operatTime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="是否删除(0:有效 1:删除)" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="isDelete" />
|
||||
<option name="type" value="java.lang.Integer" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课程id " />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="curriculumId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="企业ID" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="corpinfoId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="排序" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="sort" />
|
||||
<option name="type" value="java.lang.Integer" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="上级ID" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="parentId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="coursewarename" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件文件路径" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="videofiles" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件课时,单位分钟" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="classhour" />
|
||||
<option name="type" value="java.lang.Double" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件视频时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="videotime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="视频课件id" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="videocoursewareId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="资源库id" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="resId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="加入本地时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="downloadtime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="加入人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="downloador" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课程来源 1-资源库" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="source" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
</list>
|
||||
</option>
|
||||
<option name="name" value="BusChapterCopy1" />
|
||||
<option name="preName" value="" />
|
||||
<option name="saveModelName" value="edu_videoresource" />
|
||||
<option name="savePackageName" value="com.zcloud.modules.qps" />
|
||||
<option name="savePath" value="./src/main/java/com/zcloud/modules/qps" />
|
||||
<option name="templateGroupName" value="zcloud" />
|
||||
</TableInfoDTO>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="videoresource.bus_customerfactory">
|
||||
<value>
|
||||
<TableInfoDTO>
|
||||
<option name="comment" value="客户信息补充表" />
|
||||
<option name="fullColumn">
|
||||
<list>
|
||||
<ColumnInfoDTO>
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="customerfactoryId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="添加人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="creator" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="添加时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="createTime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="修改人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="operator" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="修改时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="operatTime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="是否删除" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="isDelete" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="bus_customer_info表主键" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="customerinfoId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="企业ID(组织机构代码)" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="corpinfoId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="企业名称(客户单位名称)" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="corpinfoName" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课程数" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="curriculumNumber" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件费用" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="cost" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="流量数(流量总)" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="flow" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="流量总费用" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="flowCost" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="总费用" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="amount" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件数" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="coursewareNumber" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="状态" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="state" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="类型" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="type" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
</list>
|
||||
</option>
|
||||
<option name="name" value="BusCustomerfactory" />
|
||||
<option name="preName" value="" />
|
||||
<option name="saveModelName" value="edu_videoresource" />
|
||||
<option name="savePackageName" value="com.zcloud.modules.custormerInfo" />
|
||||
<option name="savePath" value="./src/main/java/com/zcloud/modules/custormerInfo" />
|
||||
<option name="templateGroupName" value="zcloud" />
|
||||
</TableInfoDTO>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="videoresource.bus_videocourseware_copy1">
|
||||
<value>
|
||||
<TableInfoDTO>
|
||||
<option name="comment" value="没用" />
|
||||
<option name="fullColumn">
|
||||
<list>
|
||||
<ColumnInfoDTO>
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="videocoursewareId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="coursewarename" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="主讲人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="speaker" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件介绍" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="coursewareintroduce" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="阿里云视频id(默认模板)" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="videofiles" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课件截图" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="videocapture" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="使用人员" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="videousers" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="添加人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="creator" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="创建人名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="creatorName" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="添加时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="creattime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="修改人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="operator" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="修改人名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="operatorName" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="修改时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="operattime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="是否删除(0:有效 1:删除)" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="isdelete" />
|
||||
<option name="type" value="java.lang.Integer" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="企业ID" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="corpinfoId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="培训行业类型" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="traintype" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="岗位培训类型(别名:岗位)" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="posttype" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="岗位名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="postName" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="大纲类型" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="ontlinetype" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课时,单位分钟" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="classhour" />
|
||||
<option name="type" value="java.lang.Double" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="0-启用 1-禁用" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="state" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="是否已被售卖(0-为售卖,1-已售卖)" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="status" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="是否翻录" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="renovateFlag" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="翻新时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="renovateTime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="翻录的视频id" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="renovateId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="视频时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="videotime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="行业类型1" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="industry1" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="行业类型2" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="industry2" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="行业类型3" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="industry3" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="行业类型名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="industryAllName" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="资源库id" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="resId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="加入本地时间" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="downloadtime" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="加入人" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="downloador" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课程来源 1-资源库" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="source" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="视频存储路径" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="filePath" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="视频远程播放路径" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="remoteFilePath" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="文件名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="fileName" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课程类型" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="typeId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="课程类型名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="typeName" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="行业类型" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="industryType" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="行业名称" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="industryName" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="标签" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="labels" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="翻录根课件ID" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="renovateRootId" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="翻录版本" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="renovateVersion" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
<ColumnInfoDTO>
|
||||
<option name="comment" value="上传课件原名" />
|
||||
<option name="custom" value="false" />
|
||||
<option name="ext" value="{}" />
|
||||
<option name="name" value="coursewareNameOld" />
|
||||
<option name="type" value="java.lang.String" />
|
||||
</ColumnInfoDTO>
|
||||
</list>
|
||||
</option>
|
||||
<option name="name" value="BusVideocoursewareCopy1" />
|
||||
<option name="preName" value="" />
|
||||
<option name="saveModelName" value="edu_videoresource" />
|
||||
<option name="savePackageName" value="com.zcloud.modules.qps" />
|
||||
<option name="savePath" value="./src/main/java/com/zcloud/modules/qps" />
|
||||
<option name="templateGroupName" value="zcloud" />
|
||||
</TableInfoDTO>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="public" />
|
||||
<option name="name" value="aliyun nexus" />
|
||||
<option name="url" value="https://maven.aliyun.com/repository/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,465 @@
|
|||
<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>org.example</groupId>
|
||||
<artifactId>shopping_mall</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>shopping_mall</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.6</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<mybatisplus.version>3.4.3.2</mybatisplus.version>
|
||||
<mysql.version>8.0.28</mysql.version>
|
||||
<mssql.version>4.0</mssql.version>
|
||||
<oracle.version>11.2.0.3</oracle.version>
|
||||
<druid.version>1.2.20</druid.version>
|
||||
<quartz.version>2.3.0</quartz.version>
|
||||
<commons.lang.version>2.6</commons.lang.version>
|
||||
<commons.fileupload.version>1.2.2</commons.fileupload.version>
|
||||
<commons.io.version>2.8.0</commons.io.version>
|
||||
<commons.codec.version>1.10</commons.codec.version>
|
||||
<commons.configuration.version>1.10</commons.configuration.version>
|
||||
<shiro.version>1.9.0</shiro.version>
|
||||
<jwt.version>0.7.0</jwt.version>
|
||||
<kaptcha.version>0.0.9</kaptcha.version>
|
||||
<qiniu.version>7.2.23</qiniu.version>
|
||||
<aliyun.oss.version>3.10.2</aliyun.oss.version>
|
||||
<qcloud.cos.version>4.4</qcloud.cos.version>
|
||||
<swagger.version>2.7.0</swagger.version>
|
||||
<joda.time.version>2.9.9</joda.time.version>
|
||||
<gson.version>2.8.5</gson.version>
|
||||
<fastjson.version>1.2.79</fastjson.version>
|
||||
<hutool.version>4.1.1</hutool.version>
|
||||
<lombok.version>1.18.4</lombok.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- DevTools 热部署 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- 建康检查 接入prometheus -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<!-- es -->
|
||||
<dependency>
|
||||
<groupId>co.elastic.clients</groupId>
|
||||
<artifactId>elasticsearch-java</artifactId>
|
||||
<version>8.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.json</groupId>
|
||||
<artifactId>jakarta.json-api</artifactId>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||
<version>1.8.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatisplus.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
</dependency>
|
||||
<!--mssql驱动-->
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>sqljdbc4</artifactId>
|
||||
<version>${mssql.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>${druid.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.quartz-scheduler</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
<version>${quartz.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.mchange</groupId>
|
||||
<artifactId>c3p0</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>${commons.lang.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>${commons.fileupload.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>${commons.codec.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
<version>${commons.configuration.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<version>${shiro.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring</artifactId>
|
||||
<version>${shiro.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.axet</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>${kaptcha.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.qiniu</groupId>
|
||||
<artifactId>qiniu-java-sdk</artifactId>
|
||||
<version>${qiniu.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun.oss</groupId>
|
||||
<artifactId>aliyun-sdk-oss</artifactId>
|
||||
<version>${aliyun.oss.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<version>${qcloud.cos.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${joda.time.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--阿里云短信-->
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-core</artifactId>
|
||||
<version>4.4.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--微信支付-->
|
||||
<dependency>
|
||||
<groupId>com.github.wechatpay-apiv3</groupId>
|
||||
<artifactId>wechatpay-apache-httpclient</artifactId>
|
||||
<version>0.4.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>4.10.124.ALL</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MP4视频解析 -->
|
||||
<dependency>
|
||||
<groupId>ws.schild</groupId>
|
||||
<artifactId>jave-all-deps</artifactId>
|
||||
<version>2.6.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun.vod</groupId>
|
||||
<artifactId>aliyun-java-vod-upload</artifactId>
|
||||
<version>1.4.15</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>vod20170321</artifactId>
|
||||
<version>2.16.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-vod</artifactId>
|
||||
<version>2.15.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>alibabacloud-vod20170321</artifactId>
|
||||
<version>1.0.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>3.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- easypoi导出插件 -->
|
||||
<dependency>
|
||||
<groupId>cn.afterturn</groupId>
|
||||
<artifactId>easypoi-spring-boot-starter</artifactId>
|
||||
<version>4.4.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml-schemas</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- json转对象 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.13.2</version>
|
||||
</dependency>
|
||||
<!-- excel导入导出 -->
|
||||
<dependency>
|
||||
<groupId>com.github.stupdit1t</groupId>
|
||||
<artifactId>poi-excel</artifactId>
|
||||
<version>3.0.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.yulichang</groupId>
|
||||
<artifactId>mybatis-plus-join-core</artifactId>
|
||||
<version>1.4.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.yulichang</groupId>
|
||||
<artifactId>mybatis-plus-join-boot-starter</artifactId>
|
||||
<version>1.4.11</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!--多环境⽂件配置-->
|
||||
<profiles>
|
||||
<!--开发环境-->
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<activation>
|
||||
<!--默认激活-->
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<spring.profiles.active>dev</spring.profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>test</id>
|
||||
<properties>
|
||||
<spring.profiles.active>test</spring.profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
<!--正式环境-->
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<properties>
|
||||
<spring.profiles.active>prod</spring.profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<extensions>
|
||||
<extension>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-ssh</artifactId>
|
||||
<version>2.8</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.6.6</version>
|
||||
<configuration>
|
||||
<fork>true</fork>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- 跳过单元测试 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.spotify</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<version>0.4.14</version>
|
||||
<!--<executions>-->
|
||||
<!--<execution>-->
|
||||
<!--<phase>package</phase>-->
|
||||
<!--<goals>-->
|
||||
<!--<goal>build</goal>-->
|
||||
<!--</goals>-->
|
||||
<!--</execution>-->
|
||||
<!--</executions>-->
|
||||
<configuration>
|
||||
<imageName>shopping_mall</imageName>
|
||||
<dockerDirectory>${project.basedir}</dockerDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>/</targetPath>
|
||||
<directory>${project.build.directory}</directory>
|
||||
<include>${project.build.finalName}.jar</include>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
<!-- 运行命令 mvn clean package docker:build 打包并生成docker镜像 -->
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>public</id>
|
||||
<name>aliyun nexus</name>
|
||||
<url>https://maven.aliyun.com/repository/public/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>public</id>
|
||||
<name>aliyun nexus</name>
|
||||
<url>https://maven.aliyun.com/repository/public/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.zcloud;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableAsync
|
||||
public class MainApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MainApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.zcloud;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* 说明:项目以war包方式运行时用到
|
||||
*/
|
||||
public class SpringBootStartApplication extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
|
||||
return builder.sources(MainApplication.class); //这里要指向原先用main方法执行的FHmainApplication启动类
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.zcloud.common.alipay;
|
||||
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
import com.alipay.api.request.AlipayTradePagePayRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
/**
|
||||
* 提供支付宝相关的一些对象
|
||||
*/
|
||||
@Configuration
|
||||
public class AliBeanUtils {
|
||||
@Autowired
|
||||
private AliPayBean aliPayBean;
|
||||
//创建支付宝需要的客户端对象
|
||||
@Bean
|
||||
public AlipayClient alipayClient(){
|
||||
return new DefaultAlipayClient(aliPayBean.getAliDomain(),aliPayBean.getAppId(),aliPayBean.getMerchantPrivateKey(),"json","utf-8",
|
||||
aliPayBean.getAlipayPublicKey(),"RSA2");
|
||||
}
|
||||
//创建一个支付宝的请求对象
|
||||
@Bean
|
||||
public AlipayTradePagePayRequest alipayTradePagePayRequest(){
|
||||
return new AlipayTradePagePayRequest();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.zcloud.common.alipay;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/12/07 14:58
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "alipay")
|
||||
@Component
|
||||
@Data
|
||||
public class AliPayBean {
|
||||
private String appId;
|
||||
private String merchantPrivateKey;
|
||||
private String alipayPublicKey;
|
||||
private String httpProxyDomain;
|
||||
private String aliDomain;
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.zcloud.common.alipay;
|
||||
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.domain.AlipayTradePagePayModel;
|
||||
import com.alipay.api.request.AlipayTradeAppPayRequest;
|
||||
import com.alipay.api.request.AlipayTradePagePayRequest;
|
||||
import com.alipay.api.request.AlipayTradeWapPayRequest;
|
||||
import com.alipay.api.response.AlipayTradeWapPayResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/12/07 14:59
|
||||
*/
|
||||
@Component
|
||||
public class AliPayUtil {
|
||||
@Autowired
|
||||
private AliPayBean aliPayBean;
|
||||
@Resource
|
||||
private AlipayClient alipayClient;
|
||||
|
||||
public String pay(String outTradeNo, String totalAmount,String subject,String userAgent,String notify) throws AlipayApiException {
|
||||
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
|
||||
model.setOutTradeNo(outTradeNo);
|
||||
model.setTotalAmount(totalAmount);
|
||||
model.setSubject(subject);
|
||||
model.setProductCode("FAST_INSTANT_TRADE_PAY");
|
||||
model.setTimeoutExpress("5m"); //设置订单5分钟后失效
|
||||
// if(userAgent.contains("Windows")){
|
||||
// AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
|
||||
// alipayTradePagePayRequest.setNotifyUrl(aliPayBean.getHttpProxyDomain()+"/pay/alipay/notify");
|
||||
// alipayTradePagePayRequest.setBizModel(model);
|
||||
// return alipayClient.pageExecute(alipayTradePagePayRequest).getBody();
|
||||
// }else{
|
||||
AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();
|
||||
alipayTradeWapPayRequest.setNotifyUrl(aliPayBean.getHttpProxyDomain()+notify);
|
||||
alipayTradeWapPayRequest.setBizModel(model);
|
||||
return alipayClient.pageExecute(alipayTradeWapPayRequest).getBody();
|
||||
// }
|
||||
|
||||
// response.setContentType("text/html;charset=utf-8");
|
||||
// response.getWriter().write(result);
|
||||
// response.getWriter().flush();
|
||||
// response.getWriter().close();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.zcloud.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 实体类属性注解(用于课程、课件 的 入库、编辑使用)
|
||||
* @author zhangyue
|
||||
* @date 2024/4/9 17:16
|
||||
*/
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface EntityProperty {
|
||||
// 是否升级版本字段
|
||||
boolean isUpgradeVersion() default false;
|
||||
|
||||
|
||||
// 是否入库必须字段
|
||||
boolean isWarehouse() default false;
|
||||
|
||||
// 是否审核
|
||||
boolean isExamine() default true;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.zcloud.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 系统日志注解
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface SysLog {
|
||||
String value() default "";
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.zcloud.common.aspect;
|
||||
|
||||
import com.zcloud.common.utils.HttpContextUtils;
|
||||
import com.zcloud.modules.exceptionLog.dao.ErrorLogDao;
|
||||
import com.zcloud.modules.exceptionLog.entity.ErrorLogEntity;
|
||||
import com.zcloud.modules.exceptionLog.service.ErrorLogService;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class ExceptionLoggingAspect {
|
||||
|
||||
public ExceptionLoggingAspect(ErrorLogDao errorLogDao) {
|
||||
}
|
||||
|
||||
// 拦截modules包下所有类的所有方法
|
||||
@Pointcut("within(com.zcloud.modules..*)")
|
||||
public void modulePointCut() {
|
||||
}
|
||||
// 捕获方法执行异常
|
||||
/*@AfterThrowing(pointcut = "modulePointCut()", throwing = "e")
|
||||
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
|
||||
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
|
||||
Map<String, String[]> map = request.getParameterMap();
|
||||
Object userId = map.get("userId");
|
||||
userId = (userId != null) ? userId : ""; // 使用默认值作为后备
|
||||
ErrorLogEntity errorLog = new ErrorLogEntity();
|
||||
errorLog.setId(UUID.randomUUID().toString());
|
||||
errorLog.setLogTime(new Date());
|
||||
errorLog.setUserId(userId.toString());
|
||||
errorLog.setExceptionText(e.getMessage().toString());
|
||||
// 创建并保存异常日志
|
||||
errorLogDao.insert(errorLog);
|
||||
|
||||
}*/
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
|
||||
package com.zcloud.common.aspect;
|
||||
|
||||
import com.zcloud.common.exception.ZException;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Redis切面处理类
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Aspect
|
||||
@Configuration
|
||||
public class RedisAspect {
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
//是否开启redis缓存 true开启 false关闭
|
||||
@Value("${spring.redis.open: false}")
|
||||
private boolean open;
|
||||
|
||||
@Around("execution(* com.zcloud.common.utils.RedisUtils.*(..))")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
Object result = null;
|
||||
if(open){
|
||||
try{
|
||||
result = point.proceed();
|
||||
}catch (Exception e){
|
||||
logger.error("redis error", e);
|
||||
throw new ZException("Redis服务异常");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package com.zcloud.common.aspect;
|
||||
import com.google.gson.Gson;
|
||||
import com.zcloud.common.annotation.SysLog;
|
||||
import com.zcloud.common.utils.HttpContextUtils;
|
||||
import com.zcloud.common.utils.IPUtils;
|
||||
import com.zcloud.modules.sys.entity.SysLogEntity;
|
||||
import com.zcloud.modules.sys.entity.SysUserEntity;
|
||||
import com.zcloud.modules.sys.service.SysLogService;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 系统日志,切面处理类
|
||||
*
|
||||
*/
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class SysLogAspect {
|
||||
@Autowired
|
||||
private SysLogService sysLogService;
|
||||
|
||||
@Pointcut("@annotation(com.zcloud.common.annotation.SysLog)")
|
||||
public void logPointCut() {
|
||||
|
||||
}
|
||||
|
||||
@Around("logPointCut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
long beginTime = System.currentTimeMillis();
|
||||
//执行方法
|
||||
Object result = point.proceed();
|
||||
//执行时长(毫秒)
|
||||
long time = System.currentTimeMillis() - beginTime;
|
||||
|
||||
//保存日志
|
||||
saveSysLog(point, time);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
|
||||
SysLogEntity sysLog = new SysLogEntity();
|
||||
SysLog syslog = method.getAnnotation(SysLog.class);
|
||||
if(syslog != null){
|
||||
//注解上的描述
|
||||
sysLog.setOperation(syslog.value());
|
||||
}
|
||||
|
||||
//请求的方法名
|
||||
String className = joinPoint.getTarget().getClass().getName();
|
||||
String methodName = signature.getName();
|
||||
sysLog.setMethod(className + "." + methodName + "()");
|
||||
|
||||
//请求的参数
|
||||
Object[] args = joinPoint.getArgs();
|
||||
try{
|
||||
String params = new Gson().toJson(args);
|
||||
sysLog.setParams(params);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//获取request
|
||||
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
|
||||
//设置IP地址
|
||||
sysLog.setIp(IPUtils.getIpAddr(request));
|
||||
|
||||
//用户名
|
||||
String username = ((SysUserEntity) SecurityUtils.getSubject().getPrincipal()).getUsername();
|
||||
sysLog.setUsername(username);
|
||||
|
||||
sysLog.setTime(time);
|
||||
sysLog.setCreateDate(new Date());
|
||||
//保存系统日志
|
||||
sysLogService.saveLog(sysLog);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
package com.zcloud.common.ddos;
|
||||
|
||||
import java.util.HashMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class AjaxResult extends HashMap<String, Object> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
public static final String CODE_TAG = "code";
|
||||
|
||||
/**
|
||||
* 返回内容
|
||||
*/
|
||||
public static final String MSG_TAG = "msg";
|
||||
|
||||
/**
|
||||
* 数据对象
|
||||
*/
|
||||
public static final String DATA_TAG = "data";
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
|
||||
*/
|
||||
public AjaxResult() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
*/
|
||||
public AjaxResult(int code, String msg) {
|
||||
super.put(CODE_TAG, code);
|
||||
super.put(MSG_TAG, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
*/
|
||||
public AjaxResult(int code, String msg, Object data) {
|
||||
super.put(CODE_TAG, code);
|
||||
super.put(MSG_TAG, msg);
|
||||
if (!ObjectUtils.isEmpty(data)) {
|
||||
super.put(DATA_TAG, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success() {
|
||||
return AjaxResult.success("操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功数据
|
||||
*
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(Object data) {
|
||||
return AjaxResult.success("操作成功", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(String msg) {
|
||||
return AjaxResult.success(msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(String msg, Object data) {
|
||||
return new AjaxResult(HttpServletResponse.SC_OK, msg, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static AjaxResult error() {
|
||||
return AjaxResult.error("操作失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(String msg) {
|
||||
return AjaxResult.error(msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(String msg, Object data) {
|
||||
return new AjaxResult(HttpServletResponse.SC_BAD_REQUEST, msg, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(int code, String msg) {
|
||||
return new AjaxResult(code, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方便链式调用
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return 数据对象
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult put(String key, Object value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.zcloud.common.ddos;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
|
||||
@Slf4j
|
||||
@UtilityClass
|
||||
public class HttpDataUtil {
|
||||
/**
|
||||
* post请求处理:获取 Body 参数,转换为SortedMap
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
private static final ObjectMapper objectMapper;
|
||||
|
||||
static {
|
||||
objectMapper = new ObjectMapper();
|
||||
// 启用特性使序列化输出的Map和集合保持有序
|
||||
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
|
||||
}
|
||||
|
||||
public static SortedMap<String, Object> getBodyParams(final HttpServletRequest request) throws IOException {
|
||||
byte[] requestBody = StreamUtils.copyToByteArray(request.getInputStream());
|
||||
String body = new String(requestBody);
|
||||
|
||||
// 使用自定义配置的ObjectMapper解析JSON为SortedMap,注意这里简化处理,实际可能需要更复杂的TypeReference来准确映射所有可能的嵌套结构
|
||||
SortedMap<String, Object> params = objectMapper.readValue(body,
|
||||
TypeFactory.defaultInstance().constructMapType(SortedMap.class, String.class, Object.class));
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* get请求处理:将URL请求参数转换成SortedMap
|
||||
*/
|
||||
public static SortedMap<String, Object> getUrlParams(HttpServletRequest request) {
|
||||
String param = "";
|
||||
SortedMap<String, Object> result = new TreeMap<>();
|
||||
|
||||
if (StringUtils.isEmpty(request.getQueryString())) {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
param = URLDecoder.decode(request.getQueryString(), "utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String[] params = param.split("&");
|
||||
for (String s : params) {
|
||||
String[] array=s.split("=");
|
||||
result.put(array[0], array[1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.zcloud.common.ddos;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class RequestHeader {
|
||||
private String sign ;
|
||||
private Long timestamp ;
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package com.zcloud.common.ddos;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.zcloud.common.utils.R;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.SortedMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
public class SignFilter implements Filter {
|
||||
|
||||
//从fitler配置中获取sign过期时间
|
||||
private Long expire;
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
String signTime = filterConfig.getInitParameter("expire");
|
||||
expire = Long.parseLong(signTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
|
||||
if (!"application/json".equals(servletRequest.getContentType())) {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("过滤URL:{}", httpRequest.getRequestURI());
|
||||
|
||||
HttpServletRequestWrapper requestWrapper = new SignRequestWrapper(httpRequest);
|
||||
//构建请求头
|
||||
RequestHeader requestHeader = RequestHeader.builder()
|
||||
.timestamp(Long.parseLong(httpRequest.getHeader("Timestamp")))
|
||||
.sign(httpRequest.getHeader("Sign"))
|
||||
.build();
|
||||
|
||||
//验证请求头是否存在
|
||||
if(StringUtils.isEmpty(requestHeader.getSign()) || ObjectUtils.isEmpty(requestHeader.getTimestamp()) ){
|
||||
returnFail("签名验证不通过",httpResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
/** 1.重放验证
|
||||
* 判断timestamp时间戳与当前时间是否超过30s(过期时间根据业务情况设置),如果超过了就提示签名过期。
|
||||
**/
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - requestHeader.getTimestamp() > expire) {
|
||||
returnFail("签名验证不通过",httpResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
/** 2.重复请求验证
|
||||
* 30S内重复发送的请求不再处理,提示请求已被处理,请勿重复提交
|
||||
**/
|
||||
// String redisKey = "SIGN:" + requestHeader.getSign();
|
||||
// Boolean isNew = redisTemplate.opsForValue().setIfAbsent(redisKey, "1", expire, TimeUnit.MILLISECONDS);
|
||||
//
|
||||
// if (Boolean.FALSE.equals(isNew)) {
|
||||
// returnFail("请求已被处理,请勿重复提交", httpResponse);
|
||||
// return;
|
||||
// }
|
||||
boolean accept;
|
||||
SortedMap<String, Object> paramMap;
|
||||
switch (httpRequest.getMethod()){
|
||||
case "GET":
|
||||
paramMap = HttpDataUtil.getUrlParams(requestWrapper);
|
||||
accept = SignUtil.verifySign(paramMap, requestHeader);
|
||||
break;
|
||||
case "POST":
|
||||
paramMap = HttpDataUtil.getBodyParams(requestWrapper);
|
||||
accept = SignUtil.verifySign(paramMap, requestHeader);
|
||||
break;
|
||||
default:
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
if (accept) {
|
||||
filterChain.doFilter(requestWrapper, servletResponse);
|
||||
} else {
|
||||
returnFail("签名验证不通过",httpResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void returnFail(String msg, ServletResponse response) throws IOException {
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType("application/json; charset=utf-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
String result = JSONObject.toJSONString(R.error(msg));
|
||||
out.println(result);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.zcloud.common.ddos;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class SignFilterConfiguration {
|
||||
@Value("${sign.expire}")
|
||||
private String expire;
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate; // 新增注入
|
||||
|
||||
//filter中的初始化参数
|
||||
private Map<String, String> initParametersMap = new HashMap<>();
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean contextFilterRegistrationBean() {
|
||||
initParametersMap.put("expire", expire);
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||
registration.setFilter(signFilter());
|
||||
registration.setInitParameters(initParametersMap);
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("SignFilter");
|
||||
// 设置过滤器被调用的顺序
|
||||
registration.setOrder(1);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Filter signFilter() {
|
||||
SignFilter filter = new SignFilter();
|
||||
filter.setRedisTemplate(redisTemplate);
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.zcloud.common.ddos;
|
||||
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class SignRequestWrapper extends HttpServletRequestWrapper {
|
||||
//用于将流保存下来
|
||||
private byte[] requestBody = null;
|
||||
|
||||
public SignRequestWrapper(HttpServletRequest request) throws IOException {
|
||||
super(request);
|
||||
requestBody = StreamUtils.copyToByteArray(request.getInputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
|
||||
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return bais.read();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() throws IOException {
|
||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.zcloud.common.ddos;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.shiro.crypto.hash.Md5Hash;
|
||||
import org.apache.shiro.crypto.hash.Sha256Hash;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Base64;
|
||||
import java.util.SortedMap;
|
||||
|
||||
@Slf4j
|
||||
@UtilityClass
|
||||
public class SignUtil {
|
||||
|
||||
private final String secret = "ab934679413c0fff22bb846365e14e00d8c504294760d21d660490bd43a69a90";
|
||||
/**
|
||||
* 验证签名
|
||||
* 验证算法:把timestamp + JsonUtil.object2Json(SortedMap)合成字符串,然后MD5
|
||||
*/
|
||||
@SneakyThrows
|
||||
public boolean verifySign(SortedMap<String, Object> map, RequestHeader requestHeader) {
|
||||
StringBuffer params = new StringBuffer();
|
||||
params.append(requestHeader.getTimestamp()).append(JSON.toJSONString(map)).append(secret);
|
||||
return verifySign(params, requestHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名
|
||||
*/
|
||||
public boolean verifySign(StringBuffer params, RequestHeader requestHeader) {
|
||||
log.debug("客户端签名: {}", requestHeader.getSign());
|
||||
if (StringUtils.isEmpty(params.toString())) {
|
||||
return false;
|
||||
}
|
||||
log.info("客户端上传内容: {}", params);
|
||||
String paramsSign = new Md5Hash(params.toString()).toString();
|
||||
log.info("客户端上传内容加密后的签名结果: {}", paramsSign);
|
||||
return requestHeader.getSign().equals(paramsSign);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(new Sha256Hash("兔优素材库", "zcloud88888") );
|
||||
System.out.println(new Md5Hash("1699596698610{\"inputCode\":\"1\",\"password\":\"1\",\"phone\":\"13111111111\",\"verification\":\"\"}ab934679413c0fff22bb846365e14e00d8c504294760d21d660490bd43a69a90"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
|
||||
package com.zcloud.common.exception;
|
||||
|
||||
/**
|
||||
* 自定义异常
|
||||
*
|
||||
*/
|
||||
public class ZException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String msg;
|
||||
private int code = 500;
|
||||
|
||||
public ZException(String msg) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public ZException(String msg, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public ZException(String msg, int code) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public ZException(String msg, int code, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.zcloud.common.exception;
|
||||
|
||||
import com.zcloud.common.utils.R;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||
|
||||
/**
|
||||
* 异常处理器
|
||||
*
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
public class ZExceptionHandler {
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
*/
|
||||
@ExceptionHandler(ZException.class)
|
||||
public R handleRRException(ZException e){
|
||||
R r = new R();
|
||||
r.put("code", e.getCode());
|
||||
r.put("msg", e.getMessage());
|
||||
r.put("result","failed");
|
||||
return r;
|
||||
}
|
||||
|
||||
@ExceptionHandler(NoHandlerFoundException.class)
|
||||
public R handlerNoFoundException(Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
return R.error(404, "路径不存在,请检查路径是否正确");
|
||||
}
|
||||
|
||||
@ExceptionHandler(DuplicateKeyException.class)
|
||||
public R handleDuplicateKeyException(DuplicateKeyException e){
|
||||
logger.error(e.getMessage(), e);
|
||||
return R.error("数据库中已存在该记录");
|
||||
}
|
||||
|
||||
@ExceptionHandler(AuthorizationException.class)
|
||||
public R handleAuthorizationException(AuthorizationException e){
|
||||
logger.error(e.getMessage(), e);
|
||||
return R.error("没有权限,请联系管理员授权");
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public R handleException(Exception e){
|
||||
logger.error(e.getMessage(), e);
|
||||
return R.error();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.zcloud.common.filter;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.zcloud.common.utils.R;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
@Configuration
|
||||
public class QpsLimitFilterConfiguration {
|
||||
@Autowired
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<Filter> contextQpsFilterRegistrationBean() {
|
||||
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(QpsLimitFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("QpsLimitFilter");
|
||||
registration.setOrder(2);
|
||||
return registration;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public Filter QpsLimitFilter() {
|
||||
return new QpsLimitFilter(redisTemplate);
|
||||
}
|
||||
|
||||
private class QpsLimitFilter implements Filter {
|
||||
private static final String REDIS_KEY_USED = "user_request_count:";
|
||||
private static final String REDIS_KEY_MAX = "user_request_count_max:";
|
||||
private static final long DEFAULT_MAX_QPS = 10000000; // 最大QPS设为10
|
||||
private static final int EXPIRE_TIME_IN_SECONDS = 1; // 过期时间设为1秒
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public QpsLimitFilter(RedisTemplate<String, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
String corpinfoId = request.getParameter("corpinfoId");
|
||||
String redisKey = REDIS_KEY_USED + corpinfoId;
|
||||
|
||||
ValueOperations<String, Object> ops = redisTemplate.opsForValue();
|
||||
Long count = ops.increment(redisKey, 1L); // 自增计数器
|
||||
|
||||
// 从 Redis 中获取对应 corpinfo_id 的 MAX_QPS 值
|
||||
Object maxQpsObj = redisTemplate.opsForValue().get(REDIS_KEY_MAX + corpinfoId);
|
||||
Long maxQps = DEFAULT_MAX_QPS;
|
||||
if(maxQpsObj == null){
|
||||
// TODO 查询 数据库内的值
|
||||
}else if (maxQpsObj instanceof String) {
|
||||
maxQps = Long.parseLong((String) maxQpsObj);
|
||||
} else {
|
||||
// 处理异常情况,比如类型不匹配
|
||||
maxQps = DEFAULT_MAX_QPS;
|
||||
}
|
||||
|
||||
if (count != null && count > maxQps) {
|
||||
// 超过最大QPS,返回错误信息或者进行其他处理
|
||||
returnFail("请求过于频繁,请稍后再试",response);
|
||||
return;
|
||||
}
|
||||
|
||||
// 第一次访问时设置过期时间
|
||||
if (count == 1) {
|
||||
redisTemplate.expire(redisKey, EXPIRE_TIME_IN_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private void returnFail(String msg, ServletResponse response) throws IOException {
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType("application/json; charset=utf-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
String result = JSONObject.toJSONString(R.error(msg));
|
||||
out.println(result);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig config) throws ServletException {
|
||||
}
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.zcloud.common.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@Component
|
||||
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
|
||||
|
||||
/**
|
||||
* Converter for support http request with header Content-Type: multipart/form-data
|
||||
*/
|
||||
public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
|
||||
super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canWrite(MediaType mediaType) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.zcloud.common.handler;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.zcloud.common.utils.DateUtil;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Component
|
||||
public class MyMetaObjectHandler implements MetaObjectHandler {
|
||||
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
// this.setFieldValByName("isDelete", 0, metaObject);
|
||||
this.setFieldValByName("createTime", DateUtil.date2Str(new Date()), metaObject);
|
||||
this.setFieldValByName("operatTime", DateUtil.date2Str(new Date()), metaObject);
|
||||
this.strictInsertFill(metaObject, "isDelete", Integer.class, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
this.setFieldValByName("operatTime", DateUtil.date2Str(new Date()), metaObject);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
package com.zcloud.common.handler;
|
||||
|
||||
import cn.hutool.log.Log;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.zcloud.common.utils.HttpRequestUtil;
|
||||
import com.zcloud.common.utils.MD5;
|
||||
import com.zcloud.common.utils.PageUtils;
|
||||
import com.zcloud.common.utils.R;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/10/19 10:44
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "customer")
|
||||
@Component
|
||||
public class PlatVideoHandler {
|
||||
private String id;
|
||||
private String secret_key;
|
||||
private String url;
|
||||
private String domain;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getSecret_key() {
|
||||
return secret_key;
|
||||
}
|
||||
|
||||
public void setSecret_key(String secret_key) {
|
||||
this.secret_key = secret_key;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public PageUtils syncCurList(Map<String, Object> params) {
|
||||
HashMap<String, String> request = new HashMap<>();
|
||||
request.put("id", id);
|
||||
String key = MD5.md5(secret_key + domain);
|
||||
request.put("SECRET_KEY", key);
|
||||
if(params.get("name")!=null) request.put("KEYWORDS", params.get("name").toString());
|
||||
request.put("showCount", params.get("curPage").toString());
|
||||
request.put("currentPage", params.get("limit").toString());
|
||||
String _response = HttpRequestUtil.doPost(url + "/curriculum/getCurList", JSONObject.toJSONString(request));
|
||||
JSONObject responseResult = JSONObject.parseObject(_response);
|
||||
System.out.println(responseResult);
|
||||
Page page = new Page();
|
||||
page.setRecords(responseResult.getJSONArray("curriculumList"));
|
||||
page.setTotal(Long.parseLong(responseResult.getJSONObject("page").getString("totalResult")));
|
||||
page.setSize(Long.parseLong(params.get("limit").toString()));
|
||||
page.setCurrent(Long.parseLong(responseResult.getJSONObject("page").getString("currentPage")));
|
||||
page.setPages(Long.parseLong(responseResult.getJSONObject("page").getString("totalPage")));
|
||||
return new PageUtils(page);
|
||||
}
|
||||
|
||||
public JSONObject syncCurInfo(Map<String, Object> params) {
|
||||
HashMap<String, String> request = new HashMap<>();
|
||||
request.put("CURRICULUM_ID", params.get("curriculum_id").toString());
|
||||
request.put("id", id);
|
||||
String key = MD5.md5(secret_key + domain);
|
||||
request.put("SECRET_KEY", key);
|
||||
String _response = HttpRequestUtil.doPost(url + "/curriculum/getCurInfo", JSONObject.toJSONString(request));
|
||||
JSONObject responseResult = JSONObject.parseObject(_response);
|
||||
System.out.println(responseResult);
|
||||
if(responseResult != null && responseResult.get("code") != null && StringUtils.isNotBlank(responseResult.get("code").toString()) && "0".equals(responseResult.get("code"))){
|
||||
return responseResult;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public R syncVideoPlayAuth(Map<String, Object> video) {
|
||||
HashMap<String, String> request = new HashMap<>();
|
||||
request.put("id", this.id);
|
||||
request.put("videoId", video.get("videocourseware_id_remote").toString());
|
||||
request.put("curriculumId", video.get("curriculum_id_remote").toString());
|
||||
request.put("type", "0");
|
||||
String key = MD5.md5(secret_key + domain);
|
||||
request.put("SECRET_KEY", key);
|
||||
String _response = HttpRequestUtil.doPost(url + "/videoCourseware/getPlayInfo", JSONObject.toJSONString(request));
|
||||
Map response = JSONObject.parseObject(_response, Map.class);
|
||||
return R.ok().put("responseBody",response);
|
||||
}
|
||||
|
||||
/**
|
||||
* description: 获取视频封面<p/>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public Map syncVideoInfo(Map video) {
|
||||
HashMap<String, String> request = new HashMap<>();
|
||||
request.put("id", id);
|
||||
request.put("videoId", video.get("videocourseware_id_remote").toString());
|
||||
request.put("curriculumId", video.get("curriculum_id_remote").toString());
|
||||
request.put("type", "0");
|
||||
String key = MD5.md5(secret_key + domain);
|
||||
request.put("SECRET_KEY", key);
|
||||
String _response = HttpRequestUtil.doPost(url + "/videoCourseware/getPlayUrl", JSONObject.toJSONString(request));
|
||||
Map response = JSONObject.parseObject(_response, Map.class);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.zcloud.common.lib;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ConfigurationProperties(prefix = "lib")
|
||||
@Component
|
||||
@Data
|
||||
public class LibBean {
|
||||
private String url;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.zcloud.common.middleware;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/12/04 11:07
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "middleware")
|
||||
@Component
|
||||
@Data
|
||||
public class MiddlewareBean {
|
||||
private String url;
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.zcloud.common.threadPool;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author zhangyue
|
||||
* @date 2024/3/30 15:57
|
||||
*/
|
||||
|
||||
public class ThreadPoolProperties {
|
||||
private int coreSize;
|
||||
private int maxSize;
|
||||
private int queueCapacity;
|
||||
private int keepAlive;
|
||||
private String threadNamePrefix;
|
||||
|
||||
public int getCoreSize() {
|
||||
return coreSize;
|
||||
}
|
||||
|
||||
public void setCoreSize(int coreSize) {
|
||||
this.coreSize = coreSize;
|
||||
}
|
||||
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
public void setMaxSize(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
public int getQueueCapacity() {
|
||||
return queueCapacity;
|
||||
}
|
||||
|
||||
public void setQueueCapacity(int queueCapacity) {
|
||||
this.queueCapacity = queueCapacity;
|
||||
}
|
||||
|
||||
public int getKeepAlive() {
|
||||
return keepAlive;
|
||||
}
|
||||
|
||||
public void setKeepAlive(int keepAlive) {
|
||||
this.keepAlive = keepAlive;
|
||||
}
|
||||
|
||||
public String getThreadNamePrefix() {
|
||||
return threadNamePrefix;
|
||||
}
|
||||
|
||||
public void setThreadNamePrefix(String threadNamePrefix) {
|
||||
this.threadNamePrefix = threadNamePrefix;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
/**通常mysql中AES加密,和java中不⼀致,
|
||||
* 也就是说mysql中AES加密的东西,copy出来,
|
||||
* ⽤java代码不能解密
|
||||
* 下⾯⼤佬就来秀⼀波操作
|
||||
* */
|
||||
public class AesEncryptor {
|
||||
|
||||
private static String AESCODE = "UTF-8";
|
||||
|
||||
public static SecretKeySpec generateMySQLAESKey(final String key, final String encoding) {
|
||||
try {
|
||||
final byte[] finalKey = new byte[16];
|
||||
int i = 0;
|
||||
for(byte b : key.getBytes(encoding))
|
||||
finalKey[i++%16] ^= b;
|
||||
return new SecretKeySpec(finalKey, "AES");
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/**AES 解密
|
||||
* data : 待解密的数据
|
||||
* */
|
||||
public static String decrpt(String AESKEY, String data) throws Exception {
|
||||
// Decrypt
|
||||
final Cipher decryptCipher = Cipher.getInstance("AES");
|
||||
decryptCipher.init(Cipher.DECRYPT_MODE, generateMySQLAESKey(AESKEY, AESCODE));
|
||||
return new String(decryptCipher.doFinal(Hex.decodeHex(data.toCharArray())));
|
||||
}
|
||||
/**AES加密
|
||||
* AESKEY: KEY
|
||||
* data : 待加密的数据
|
||||
* */
|
||||
public static String encrpt(String AESKEY,String data) throws Exception {
|
||||
// Encrypt
|
||||
final Cipher encryptCipher = Cipher.getInstance("AES");
|
||||
encryptCipher.init(Cipher.ENCRYPT_MODE, generateMySQLAESKey(AESKEY, AESCODE));
|
||||
char[] code= Hex.encodeHex(encryptCipher.doFinal(data.getBytes(AESCODE)));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for(char d:code) {
|
||||
builder.append(d);
|
||||
}
|
||||
String strning = builder.toString();
|
||||
return strning;
|
||||
}
|
||||
public static void main(String... args) throws Exception {
|
||||
System.out.println(encrpt("13133333333","113485")); //加密
|
||||
|
||||
System.out.println(decrpt("13133333333","a6e6937a44ce951209adb197963fb418ed6145918cf3df80ca040ed26f8829ae"));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.aliyun.auth.credentials.Credential;
|
||||
import com.aliyun.auth.credentials.provider.StaticCredentialProvider;
|
||||
import com.aliyun.sdk.service.vod20170321.AsyncClient;
|
||||
import com.aliyun.teaopenapi.models.Config;
|
||||
import com.aliyun.teautil.models.RuntimeOptions;
|
||||
import com.aliyun.vod.upload.impl.UploadVideoImpl;
|
||||
import com.aliyun.vod.upload.req.UploadStreamRequest;
|
||||
import com.aliyun.vod.upload.resp.UploadStreamResponse;
|
||||
import com.aliyun.vod20170321.Client;
|
||||
import com.aliyun.vod20170321.models.*;
|
||||
import com.aliyuncs.DefaultAcsClient;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import com.aliyuncs.profile.DefaultProfile;
|
||||
import com.google.gson.Gson;
|
||||
import darabonba.core.client.ClientOverrideConfiguration;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.aliyun.sdk.service.vod20170321.models.DescribeVodDomainUsageDataResponseBody.DataModule;
|
||||
import com.aliyun.sdk.service.vod20170321.models.DescribeVodDomainUsageDataResponse;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/12/13 14:26
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "aliplay")
|
||||
@Component
|
||||
@Data
|
||||
public class AliVideoUtil {
|
||||
private String accessKeyId;
|
||||
private String accessKeySecret;
|
||||
private String templateGroupId;
|
||||
private String sdTemplateGroupId;
|
||||
private String ldTemplateGroupId;
|
||||
private String regionId;
|
||||
private String endpoint;
|
||||
private String shangHaiRegionId;
|
||||
private String shangHaiEndpoint;
|
||||
|
||||
public DefaultAcsClient initVodClient() throws ClientException {
|
||||
DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
|
||||
DefaultAcsClient client = new DefaultAcsClient(profile);
|
||||
return client;
|
||||
}
|
||||
public Client createClient() throws Exception {
|
||||
Config config = new Config()
|
||||
.setAccessKeyId(this.accessKeyId)
|
||||
.setAccessKeySecret(this.accessKeySecret);
|
||||
// 访问的域名
|
||||
config.endpoint = this.endpoint;
|
||||
return new com.aliyun.vod20170321.Client(config);
|
||||
}
|
||||
public AsyncClient createTrafficClient() throws Exception {
|
||||
|
||||
// Configure Credentials authentication information, including ak, secret, token
|
||||
StaticCredentialProvider provider = StaticCredentialProvider.create(Credential.builder()
|
||||
// Please ensure that the environment variables ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET are set.
|
||||
.accessKeyId(this.accessKeyId)
|
||||
.accessKeySecret(this.accessKeySecret)
|
||||
//.securityToken(System.getenv("ALIBABA_CLOUD_SECURITY_TOKEN")) // use STS token
|
||||
.build());
|
||||
|
||||
// Configure the Client
|
||||
AsyncClient client = AsyncClient.builder()
|
||||
.region(this.shangHaiRegionId) // Region ID
|
||||
//.httpClient(httpClient) // Use the configured HttpClient, otherwise use the default HttpClient (Apache HttpClient)
|
||||
.credentialsProvider(provider)
|
||||
//.serviceConfiguration(Configuration.create()) // Service-level configuration
|
||||
// Client-level configuration rewrite, can set Endpoint, Http request parameters, etc.
|
||||
.overrideConfiguration(
|
||||
ClientOverrideConfiguration.create()
|
||||
// Endpoint 请参考 https://api.aliyun.com/product/vod
|
||||
.setEndpointOverride(this.shangHaiEndpoint)
|
||||
//.setConnectTimeout(Duration.ofSeconds(30))
|
||||
)
|
||||
.build();
|
||||
return client;
|
||||
}
|
||||
|
||||
//流方式上传视频
|
||||
public Map<String, String> uploadVideo(String title, String fileName, InputStream inputStream) throws Exception {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
UploadStreamRequest request = new UploadStreamRequest(this.accessKeyId, this.accessKeySecret, title, fileName, new BufferedInputStream(inputStream));
|
||||
request.setShowWaterMark(true);
|
||||
request.setTemplateGroupId(this.templateGroupId);
|
||||
request.setApiRegionId(this.regionId);
|
||||
/* 设置自定义上传进度回调(必须继承 VoDProgressListener)*/
|
||||
/*默认关闭。如果开启了这个功能,上传过程中服务端会在日志中返回上传详情。如果不需要接收此消息,需关闭此功能*/
|
||||
request.setProgressListener(new PutObjectProgressListener());
|
||||
UploadVideoImpl uploader = new UploadVideoImpl();
|
||||
UploadStreamResponse response = uploader.uploadStream(request);
|
||||
result.put("RequestId", response.getRequestId());
|
||||
if (response.isSuccess()) {
|
||||
result.put("VideoId", response.getVideoId());
|
||||
} else {
|
||||
throw new RuntimeException("ErrorCode=[" + response.getCode() + "],ErrorMessage=[" + response.getMessage() + "]");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 视频上传(不转码)
|
||||
* @param title
|
||||
* @param fileName
|
||||
* @param inputStream
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public Map<String, String> uploadVideoNoGroup(String title, String fileName, InputStream inputStream) throws Exception {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
UploadStreamRequest request = new UploadStreamRequest(this.accessKeyId, this.accessKeySecret, title, fileName, new BufferedInputStream(inputStream));
|
||||
request.setShowWaterMark(false);
|
||||
request.setApiRegionId(this.regionId);
|
||||
/* 设置自定义上传进度回调(必须继承 VoDProgressListener)*/
|
||||
/*默认关闭。如果开启了这个功能,上传过程中服务端会在日志中返回上传详情。如果不需要接收此消息,需关闭此功能*/
|
||||
request.setProgressListener(new PutObjectProgressListener());
|
||||
UploadVideoImpl uploader = new UploadVideoImpl();
|
||||
UploadStreamResponse response = uploader.uploadStream(request);
|
||||
result.put("RequestId", response.getRequestId());
|
||||
if (response.isSuccess()) {
|
||||
result.put("VideoId", response.getVideoId());
|
||||
} else {
|
||||
throw new RuntimeException("ErrorCode=[" + response.getCode() + "],ErrorMessage=[" + response.getMessage() + "]");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//获取上传地址
|
||||
// public CreateUploadVideoResponse createUploadVideo(VideoCreateForm form) throws Exception {
|
||||
// Client client = createClient();
|
||||
// CreateUploadVideoRequest createUploadVideoRequest = new CreateUploadVideoRequest()
|
||||
// .setFileName(form.getFileName())
|
||||
// .setTitle(form.getTitle())
|
||||
// .setTemplateGroupId(templateGroupId);
|
||||
// // 复制代码运行请自行打印 API 的返回值
|
||||
// CreateUploadVideoResponse resp= client.createUploadVideo(createUploadVideoRequest);
|
||||
// return resp;
|
||||
// }
|
||||
|
||||
|
||||
//获取播放地址
|
||||
public GetPlayInfoResponse getPlayInfo(String videoId) throws Exception {
|
||||
Client client = createClient();
|
||||
GetPlayInfoRequest request = new GetPlayInfoRequest();
|
||||
request.setVideoId(videoId);
|
||||
request.setResultType("Multiple");
|
||||
RuntimeOptions runtime = new RuntimeOptions();
|
||||
return client.getPlayInfoWithOptions(request,runtime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 查询转码配置的详细信息
|
||||
public void GetTranscodeTemplateGroup(String groupId) throws Exception {
|
||||
Client client = createClient();
|
||||
GetTranscodeTemplateGroupRequest getTranscodeTemplateGroupRequest = new GetTranscodeTemplateGroupRequest()
|
||||
.setTranscodeTemplateGroupId(groupId);
|
||||
RuntimeOptions runtime = new RuntimeOptions();
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
client.getTranscodeTemplateGroupWithOptions(getTranscodeTemplateGroupRequest, runtime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交转码任务
|
||||
* @param params
|
||||
* @throws Exception
|
||||
*/
|
||||
public void submitTranscodeJobs(Map<String, String> params) throws Exception {
|
||||
Client client = createClient();
|
||||
SubmitTranscodeJobsRequest submitTranscodeJobsRequest = new SubmitTranscodeJobsRequest()
|
||||
.setVideoId(params.get("videoId"))
|
||||
.setTemplateGroupId(params.get("templateGroupId"));
|
||||
RuntimeOptions runtime = new RuntimeOptions();
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
client.submitTranscodeJobsWithOptions(submitTranscodeJobsRequest, runtime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询转码任务列表
|
||||
* @param videoId
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public ListTranscodeTaskResponse ListTranscodeTask(String videoId) throws Exception {
|
||||
Client client = createClient();
|
||||
ListTranscodeTaskRequest listTranscodeTaskRequest = new ListTranscodeTaskRequest()
|
||||
.setVideoId(videoId);
|
||||
RuntimeOptions runtime = new RuntimeOptions();
|
||||
return client.listTranscodeTaskWithOptions(listTranscodeTaskRequest, runtime);
|
||||
}
|
||||
|
||||
public void GetMezzanineInfo(String videoId) throws Exception {
|
||||
Client client = createClient();
|
||||
GetMezzanineInfoRequest getMezzanineInfoRequest = new GetMezzanineInfoRequest()
|
||||
.setVideoId(videoId);
|
||||
RuntimeOptions runtime = new RuntimeOptions();
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
client.getMezzanineInfoWithOptions(getMezzanineInfoRequest, runtime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public List<DataModule> getYesterdayFlow(String domainName, String startDate, String endDate) throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("startTime", startDate + " 00:00:00");
|
||||
params.put("endTime", endDate + " 23:59:59");
|
||||
params.put("interval", "86400");
|
||||
params.put("domainName", domainName);
|
||||
DescribeVodDomainUsageDataResponse response = DescribeVodDomainUsageData(params);
|
||||
return response.getBody().getUsageDataPerInterval().getDataModule();
|
||||
}
|
||||
public DescribeVodDomainUsageDataResponse DescribeVodDomainUsageData(Map<String, String> params) throws Exception {
|
||||
AsyncClient client = createTrafficClient();
|
||||
try {
|
||||
com.aliyun.sdk.service.vod20170321.models.DescribeVodDomainUsageDataRequest describeVodDomainUsageDataRequest = com.aliyun.sdk.service.vod20170321.models.DescribeVodDomainUsageDataRequest.builder()
|
||||
.domainName(params.get("domainName").toString()) // 域名
|
||||
.area("CN")
|
||||
.type("all")
|
||||
.field("traf") //数据类型 traf:流量
|
||||
.startTime(DateUtil.parseCSTToUTC(params.get("startTime").toString())) // 获取数据起始时间点。格式为:yyyy-MM-ddTHH:mm:ssZ(UTC时间)。
|
||||
.endTime(DateUtil.parseCSTToUTC(params.get("endTime").toString())) // 获取数据结束时间点,需晚于起始时间。格式为:yyyy-MM-ddTHH:mm:ssZ(UTC时间)。
|
||||
.interval(params.get("interval").toString()) // 强制指定获取指定时间粒度的数据,单位为秒。支持300(5分钟)、3600(1小时)和86400(1天)。
|
||||
|
||||
// Request-level configuration rewrite, can set Http request parameters, etc.
|
||||
// .requestConfiguration(RequestConfiguration.crea0te().setHttpHeaders(new HttpHeaders()))
|
||||
.build();
|
||||
if(params.get("domainName") != null){
|
||||
describeVodDomainUsageDataRequest.toBuilder().domainName(params.get("domainName").toString());
|
||||
}
|
||||
// Request-level configuration rewrite, can set Http request parameters, etc.
|
||||
// .requestConfiguration(RequestConfiguration.create().setHttpHeaders(new HttpHeaders()))
|
||||
|
||||
// Asynchronously get the return value of the API request
|
||||
CompletableFuture<DescribeVodDomainUsageDataResponse> response = client.describeVodDomainUsageData(describeVodDomainUsageDataRequest);
|
||||
// Synchronously get the return value of the API request
|
||||
|
||||
DescribeVodDomainUsageDataResponse resp = response.get();
|
||||
System.out.println(new Gson().toJson(resp));
|
||||
return resp;
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.aliyuncs.DefaultAcsClient;
|
||||
import com.aliyuncs.IAcsClient;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import com.aliyuncs.exceptions.ServerException;
|
||||
import com.aliyuncs.http.MethodType;
|
||||
import com.aliyuncs.profile.DefaultProfile;
|
||||
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
|
||||
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
|
||||
import com.google.gson.Gson;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
public class AliyunSmsUtil {
|
||||
|
||||
static final String accessKeyId = "LTAIDJTv7Z3iNLyp";//LTAI4G7hRf3LqVGvobYRFxW2
|
||||
static final String accessKeySecret = "LcupykSFftCHbRvzuJIv5YWY0tWKaV";//T43mhQvHiEPt9oBmWP3BLFuqtaYKhr
|
||||
private IAcsClient client;
|
||||
|
||||
|
||||
private AliyunSmsUtil() {
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
client = new DefaultAcsClient(DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret));
|
||||
}
|
||||
|
||||
public static AliyunSmsUtil getInstance() {
|
||||
return new AliyunSmsUtil();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送国内短信
|
||||
*
|
||||
* @param phone 接收短信的手机号码
|
||||
* @param signName 短信签名名称
|
||||
* @param templateCode 短信模板CODE
|
||||
* @param templateParam 短信模板变量,Map格式
|
||||
* @return 发送结果
|
||||
*/
|
||||
public SendSmsResponse sendSms(String phone, String templateCode, Map<String, Object> templateParam) {
|
||||
SendSmsRequest request = new SendSmsRequest();
|
||||
//必填-短信接收号码
|
||||
request.setPhoneNumbers(phone);
|
||||
//必填-短信签名
|
||||
request.setSignName("兔优到家");
|
||||
//必填-短信模板Code
|
||||
request.setTemplateCode(templateCode);
|
||||
|
||||
// 必填-模板变量,JSON格式,替换模板中的变量,不需要替换的参数用空串代替
|
||||
request.setTemplateParam(new Gson().toJson(templateParam));
|
||||
try {
|
||||
return client.getAcsResponse(request);
|
||||
} catch (ServerException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClientException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送国际/港澳台短信
|
||||
*
|
||||
* @param phone 接收短信的手机号码
|
||||
* @param signName 短信签名名称
|
||||
* @param templateCode 短信模板CODE
|
||||
* @param templateParam 短信模板变量,JSON格式,例如:{\"code\":\"${code}\"}
|
||||
* @return 发送结果
|
||||
*/
|
||||
public SendSmsResponse sendInternationalSms(String phone, String signName, String templateCode, Map<String, Object> templateParam) {
|
||||
SendSmsRequest request = new SendSmsRequest();
|
||||
// 必填-国际/港澳台手机号码
|
||||
request.setPhoneNumbers(phone);
|
||||
// 必填-短信签名
|
||||
request.setSignName(signName);
|
||||
// 必填-短信模板Code
|
||||
request.setTemplateCode(templateCode);
|
||||
|
||||
// 选填-模板变量,JSON格式,替换模板中的变量,不需要替换的参数用空串代替
|
||||
request.setTemplateParam(new Gson().toJson(templateParam));
|
||||
try {
|
||||
return client.getAcsResponse(request);
|
||||
} catch (ServerException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClientException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import org.apache.shiro.codec.Base64;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* BASE64编码解码工具包
|
||||
* </p>
|
||||
*/
|
||||
public class Base64Utils {
|
||||
|
||||
/** */
|
||||
/**
|
||||
* 文件读取缓冲区大小
|
||||
*/
|
||||
private static final int CACHE_SIZE = 1024;
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* BASE64字符串解码为二进制数据
|
||||
* </p>
|
||||
*
|
||||
* @param base64
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] decode(String base64) throws Exception {
|
||||
return Base64.decode(base64.getBytes());
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 二进制数据编码为BASE64字符串
|
||||
* </p>
|
||||
*
|
||||
* @param bytes
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String encode(byte[] bytes) throws Exception {
|
||||
return new String(Base64.encode(bytes));
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 将文件编码为BASE64字符串
|
||||
* </p>
|
||||
* <p>
|
||||
* 大文件慎用,可能会导致内存溢出
|
||||
* </p>
|
||||
*
|
||||
* @param filePath
|
||||
* 文件绝对路径
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String encodeFile(String filePath) throws Exception {
|
||||
byte[] bytes = fileToByte(filePath);
|
||||
return encode(bytes);
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* BASE64字符串转回文件
|
||||
* </p>
|
||||
*
|
||||
* @param filePath
|
||||
* 文件绝对路径
|
||||
* @param base64
|
||||
* 编码字符串
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void decodeToFile(String filePath, String base64) throws Exception {
|
||||
byte[] bytes = decode(base64);
|
||||
byteArrayToFile(bytes, filePath);
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 文件转换为二进制数组
|
||||
* </p>
|
||||
*
|
||||
* @param filePath
|
||||
* 文件路径
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] fileToByte(String filePath) throws Exception {
|
||||
byte[] data = new byte[0];
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
|
||||
byte[] cache = new byte[CACHE_SIZE];
|
||||
int nRead = 0;
|
||||
while ((nRead = in.read(cache)) != -1) {
|
||||
out.write(cache, 0, nRead);
|
||||
out.flush();
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
data = out.toByteArray();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 二进制数据写文件
|
||||
* </p>
|
||||
*
|
||||
* @param bytes
|
||||
* 二进制数据
|
||||
* @param filePath
|
||||
* 文件生成目录
|
||||
*/
|
||||
public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
|
||||
InputStream in = new ByteArrayInputStream(bytes);
|
||||
File destFile = new File(filePath);
|
||||
if (!destFile.getParentFile().exists()) {
|
||||
destFile.getParentFile().mkdirs();
|
||||
}
|
||||
destFile.createNewFile();
|
||||
OutputStream out = new FileOutputStream(destFile);
|
||||
byte[] cache = new byte[CACHE_SIZE];
|
||||
int nRead = 0;
|
||||
while ((nRead = in.read(cache)) != -1) {
|
||||
out.write(cache, 0, nRead);
|
||||
out.flush();
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.zcloud.common.annotation.EntityProperty;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhangyue
|
||||
* @date 2024/4/3 15:05
|
||||
*/
|
||||
public class BeanCompareUtils {
|
||||
public static String compareObjectsName(Object object1, Object object2) throws IllegalAccessException {
|
||||
|
||||
Class<?> clazz = object1.getClass();
|
||||
|
||||
if (!clazz.equals(object2.getClass())) {
|
||||
throw new IllegalArgumentException("The two objects should be of the same class");
|
||||
}
|
||||
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
StringBuffer result = new StringBuffer();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
Object value1 = field.get(object1);
|
||||
Object value2 = field.get(object2);
|
||||
ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
|
||||
// 获取value属性的值
|
||||
String name = annotation.value();
|
||||
if(!Objects.equals(value1,value2)){
|
||||
result.append(","+name);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import org.springframework.cglib.beans.BeanCopier;
|
||||
import org.springframework.cglib.core.Converter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author liu jun
|
||||
* @description cglib包中的bean拷贝(性能优于Spring当中的BeanUtils)
|
||||
* @since 2023/3/28 14:22
|
||||
*/
|
||||
public class BeanCopierUtils {
|
||||
|
||||
|
||||
/**
|
||||
* 创建一个map来存储BeanCopier缓存
|
||||
*/
|
||||
private static final Map<String, BeanCopier> BEAN_COPIER_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 深拷贝,我们可以直接传实例化的拷贝对象和被实例化的拷贝对象进行深拷贝
|
||||
*
|
||||
* @param source 源对象
|
||||
* @param target 目标类
|
||||
*/
|
||||
private static void copy(Object source, Object target) {
|
||||
// 获取当前两者转换map对应的key
|
||||
String key = getKey(source, target);
|
||||
BeanCopier beanCopier;
|
||||
// 判断键是否存在,不存在就将BeanCopier插入到map里,存在就直接获取
|
||||
if (!BEAN_COPIER_MAP.containsKey(key)) {
|
||||
// 参数1: 源对象类 参数2: 目标对象类 参数3: 是否使用自定义转换器
|
||||
beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
|
||||
BEAN_COPIER_MAP.put(key, beanCopier);
|
||||
} else {
|
||||
beanCopier = BEAN_COPIER_MAP.get(key);
|
||||
}
|
||||
// 自定义转换器可在copy函数当中的第三个参数设置
|
||||
beanCopier.copy(source, target, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 深拷贝
|
||||
*
|
||||
* @param source 源对象
|
||||
* @param target 目标类
|
||||
* @param <T> 目标类型
|
||||
* @return 单个目标类
|
||||
*/
|
||||
public static <T> T copy(Object source, Class<T> target) {
|
||||
// 如果源对象为空,结束
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
// 用来判断目标类型空指针异常
|
||||
Objects.requireNonNull(target);
|
||||
T result = null;
|
||||
try {
|
||||
result = target.newInstance();
|
||||
copy(source, result);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* List深拷贝
|
||||
*
|
||||
* @param sources 源集合
|
||||
* @param target 目标类
|
||||
* @param <S> 源类型
|
||||
* @param <T> 目标类型
|
||||
* @return 目标类集合
|
||||
*/
|
||||
public static <S, T> List<T> copyList(List<S> sources, Class<T> target) {
|
||||
// 用来判断目标类型空指针异常
|
||||
Objects.requireNonNull(target);
|
||||
return sources.stream().map(src -> copy(src, target)).collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义类型转换器
|
||||
*
|
||||
* @param source 源对象
|
||||
* @param target 目标类
|
||||
* @param converter 转换器
|
||||
*/
|
||||
private static void copy(Object source, Object target, Converter converter) {
|
||||
if (!Objects.isNull(converter)) {
|
||||
BeanCopier beanCopier = BeanCopier.create(source.getClass(), target.getClass(), true);
|
||||
beanCopier.copy(source, target, converter);
|
||||
} else {
|
||||
copy(source, target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义类型转换器
|
||||
*
|
||||
* @param source 源对象
|
||||
* @param target 目标类
|
||||
* @param converter 转换器
|
||||
* @param <T> 目标类型
|
||||
* @return 单个目标类
|
||||
*/
|
||||
public static <T> T copy(Object source, Class<T> target, Converter converter) {
|
||||
// 如果源对象为空,结束
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
// 用来判断目标类型空指针异常
|
||||
Objects.requireNonNull(target);
|
||||
T result = null;
|
||||
try {
|
||||
result = target.newInstance();
|
||||
copy(source, result, converter);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Map中的Key
|
||||
*
|
||||
* @param source 源对象
|
||||
* @param target 目标类
|
||||
* @return 源对象与目标类名字的拼接
|
||||
*/
|
||||
private static String getKey(Object source, Object target) {
|
||||
return source.getClass().getName() + "_" + target.getClass().getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CamelCaseUtil {
|
||||
|
||||
public static <V> Map<String, V> camelToUnderline(Map<String, V> sourceMap) {
|
||||
Map<String, V> targetMap = new HashMap<>();
|
||||
for (Map.Entry<String, V> entry : sourceMap.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String newKey = camelToUnderline(key);
|
||||
targetMap.put(newKey, entry.getValue());
|
||||
}
|
||||
return targetMap;
|
||||
}
|
||||
|
||||
private static String camelToUnderline(String camelCase) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < camelCase.length(); i++) {
|
||||
char c = camelCase.charAt(i);
|
||||
if (Character.isUpperCase(c)) {
|
||||
sb.append("_").append(Character.toLowerCase(c));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Map<String, String> sourceMap = new HashMap<>();
|
||||
sourceMap.put("helloWorld", "value1");
|
||||
sourceMap.put("exampleKey", "value2");
|
||||
Map<String, String> targetMap = camelToUnderline(sourceMap);
|
||||
System.out.println(targetMap); // 输出: {hello_world=value1, example_key=value2}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Compare {
|
||||
|
||||
/**
|
||||
* 字段名称
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CompareNode {
|
||||
|
||||
/**
|
||||
* 字段
|
||||
*/
|
||||
private String fieldKey;
|
||||
|
||||
/**
|
||||
* 字段值
|
||||
*/
|
||||
private Object fieldValue;
|
||||
|
||||
/**
|
||||
* 字段名称
|
||||
*/
|
||||
private String fieldName;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
public class CompareUtils<T> {
|
||||
private static final String COMMA = ",";
|
||||
|
||||
/**
|
||||
* 属性比较
|
||||
*
|
||||
* @param source 源数据对象
|
||||
* @param target 目标数据对象
|
||||
* @return 对应属性值的比较变化
|
||||
*/
|
||||
public String compare(T source, T target) {
|
||||
return compare(source, target, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 属性比较
|
||||
*
|
||||
* @param source 源数据对象
|
||||
* @param target 目标数据对象
|
||||
* @param ignoreCompareFields 忽略比较的字段
|
||||
* @return 对应属性值的比较变化
|
||||
*/
|
||||
public String compare(T source, T target, List<String> ignoreCompareFields) {
|
||||
if (Objects.isNull(source) && Objects.isNull(target)) {
|
||||
return "";
|
||||
}
|
||||
Map<String, CompareNode> sourceMap = this.getFiledValueMap(source);
|
||||
Map<String, CompareNode> targetMap = this.getFiledValueMap(target);
|
||||
if (sourceMap.isEmpty() && targetMap.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
// 如果源数据为空,则只显示目标数据,不显示属性变化情况
|
||||
if (sourceMap.isEmpty()) {
|
||||
return doEmpty(targetMap, ignoreCompareFields);
|
||||
}
|
||||
// 如果源数据为空,则显示属性变化情况
|
||||
String s = doCompare(sourceMap, targetMap, ignoreCompareFields);
|
||||
if (!s.endsWith(COMMA)) {
|
||||
return s;
|
||||
}
|
||||
return s.substring(0, s.length() - 1);
|
||||
}
|
||||
|
||||
private String doEmpty(Map<String, CompareNode> targetMap, List<String> ignoreCompareFields) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Collection<CompareNode> values = targetMap.values();
|
||||
int size = values.size();
|
||||
int current = 0;
|
||||
for (CompareNode node : values) {
|
||||
current++;
|
||||
Object o = Optional.ofNullable(node.getFieldValue()).orElse("");
|
||||
if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(node.getFieldKey())) {
|
||||
continue;
|
||||
}
|
||||
if (o.toString().length() > 0) {
|
||||
sb.append(node.getFieldName() + ":" + o);
|
||||
if (current < size) {
|
||||
sb.append(COMMA);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String doCompare(Map<String, CompareNode> sourceMap, Map<String, CompareNode> targetMap, List<String> ignoreCompareFields) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Set<String> keys = sourceMap.keySet();
|
||||
int size = keys.size();
|
||||
int current = 0;
|
||||
for (String key : keys) {
|
||||
current++;
|
||||
CompareNode sn = sourceMap.get(key);
|
||||
CompareNode tn = targetMap.get(key);
|
||||
if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(sn.getFieldKey())) {
|
||||
continue;
|
||||
}
|
||||
String sv = Optional.ofNullable(sn.getFieldValue()).orElse("").toString();
|
||||
String tv = Optional.ofNullable(tn.getFieldValue()).orElse("").toString();
|
||||
// 只有两者属性值不一致时, 才显示变化情况
|
||||
if (!sv.equals(tv)) {
|
||||
sb.append(String.format("%s&:&%s&->&%s", sn.getFieldName(), sv, tv));
|
||||
if (current < size) {
|
||||
sb.append(COMMA);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Map<String, CompareNode> getFiledValueMap(T t) {
|
||||
if (Objects.isNull(t)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Field[] fields = t.getClass().getDeclaredFields();
|
||||
if (Objects.isNull(fields) || fields.length == 0) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, CompareNode> map = new LinkedHashMap();
|
||||
for (Field field : fields) {
|
||||
Compare compareAnnotation = field.getAnnotation(Compare.class);
|
||||
if (Objects.isNull(compareAnnotation)) {
|
||||
continue;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
String fieldKey = field.getName();
|
||||
CompareNode node = new CompareNode();
|
||||
node.setFieldKey(fieldKey);
|
||||
node.setFieldValue(field.get(t));
|
||||
node.setFieldName(compareAnnotation.value());
|
||||
map.put(field.getName(), node);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
/**
|
||||
* 系统参数相关Key
|
||||
*
|
||||
*/
|
||||
public class ConfigConstant {
|
||||
/**
|
||||
* 云存储配置KEY
|
||||
*/
|
||||
public final static String CLOUD_STORAGE_CONFIG_KEY = "CLOUD_STORAGE_CONFIG_KEY";
|
||||
// /**
|
||||
// * 本地视频存储路径
|
||||
// */
|
||||
// public final static String LOCAL_VIDEO_PATH = "D:";
|
||||
/**
|
||||
* 本地视频存储路径
|
||||
*/
|
||||
// public final static String LOCAL_VIDEO_PATH = "/mnt/kjkfile";
|
||||
public final static String LOCAL_VIDEO_PATH = "/home";
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.zcloud.common.validator.group.AliyunGroup;
|
||||
import com.zcloud.common.validator.group.QcloudGroup;
|
||||
import com.zcloud.common.validator.group.QiniuGroup;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 常量
|
||||
*/
|
||||
public class Constant {
|
||||
/**
|
||||
* 当前页码
|
||||
*/
|
||||
public static final String PAGE = "curPage";
|
||||
/**
|
||||
* 每页显示记录数
|
||||
*/
|
||||
public static final String LIMIT = "limit";
|
||||
/**
|
||||
* 排序字段
|
||||
*/
|
||||
public static final String ORDER_FIELD = "sidx";
|
||||
/**
|
||||
* 排序方式
|
||||
*/
|
||||
public static final String ORDER = "order";
|
||||
/**
|
||||
* 升序
|
||||
*/
|
||||
public static final String ASC = "asc";
|
||||
|
||||
/**
|
||||
* 菜单类型
|
||||
*
|
||||
* @author chenshun
|
||||
* @email sunlightcs@gmail.com
|
||||
* @date 2016年11月15日 下午1:24:29
|
||||
*/
|
||||
public enum MenuType {
|
||||
/**
|
||||
* 目录
|
||||
*/
|
||||
CATALOG(0),
|
||||
/**
|
||||
* 菜单
|
||||
*/
|
||||
MENU(1),
|
||||
/**
|
||||
* 按钮
|
||||
*/
|
||||
BUTTON(2);
|
||||
|
||||
private int value;
|
||||
|
||||
MenuType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务状态
|
||||
*
|
||||
* @author chenshun
|
||||
* @email sunlightcs@gmail.com
|
||||
* @date 2016年12月3日 上午12:07:22
|
||||
*/
|
||||
public enum ScheduleStatus {
|
||||
/**
|
||||
* 正常
|
||||
*/
|
||||
NORMAL(0),
|
||||
/**
|
||||
* 暂停
|
||||
*/
|
||||
PAUSE(1);
|
||||
|
||||
private int value;
|
||||
|
||||
ScheduleStatus(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单类型
|
||||
*
|
||||
* @author chenshun
|
||||
* @email sunlightcs@gmail.com
|
||||
* @date 2016年11月15日 下午1:24:29
|
||||
*/
|
||||
public enum PurposeType {
|
||||
|
||||
/**
|
||||
* 基础课程
|
||||
*/
|
||||
BASIC_COURSE("05475d27756f4b2a8e1a065cada4186b"),
|
||||
/**
|
||||
* 定制课程
|
||||
*/
|
||||
CUSTOMIZED_COURSES("069c7a3dcf714f8fb01cdce778e4b442");
|
||||
|
||||
|
||||
private String value;
|
||||
|
||||
PurposeType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 云服务商
|
||||
*/
|
||||
public enum CloudService {
|
||||
/**
|
||||
* 七牛云
|
||||
*/
|
||||
QINIU(1, QiniuGroup.class),
|
||||
/**
|
||||
* 阿里云
|
||||
*/
|
||||
ALIYUN(2, AliyunGroup.class),
|
||||
/**
|
||||
* 腾讯云
|
||||
*/
|
||||
QCLOUD(3, QcloudGroup.class);
|
||||
|
||||
private int value;
|
||||
|
||||
private Class<?> validatorGroupClass;
|
||||
|
||||
CloudService(int value, Class<?> validatorGroupClass) {
|
||||
this.value = value;
|
||||
this.validatorGroupClass = validatorGroupClass;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Class<?> getValidatorGroupClass() {
|
||||
return this.validatorGroupClass;
|
||||
}
|
||||
|
||||
public static CloudService getByValue(Integer value) {
|
||||
Optional<CloudService> first = Stream.of(CloudService.values()).filter(cs -> value.equals(cs.value)).findFirst();
|
||||
if (!first.isPresent()) {
|
||||
throw new IllegalArgumentException("非法的枚举值:" + value);
|
||||
}
|
||||
return first.get();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,457 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 说明:日期处理
|
||||
* 作者:luoxiaobao
|
||||
* 官网:www.qdkjchina.com
|
||||
*/
|
||||
public class DateUtil {
|
||||
|
||||
private final static SimpleDateFormat sdfYear = new SimpleDateFormat("yyyy");
|
||||
private final static SimpleDateFormat sdfDay = new SimpleDateFormat("yyyy-MM-dd");
|
||||
private final static SimpleDateFormat sdfDays = new SimpleDateFormat("yyyyMMdd");
|
||||
private final static SimpleDateFormat sdfTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
private final static SimpleDateFormat sdfTimes = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
private final static SimpleDateFormat utsTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
|
||||
/**
|
||||
* 获取YYYY格式
|
||||
* @return
|
||||
*/
|
||||
public static String getSdfTimes() {
|
||||
return sdfTimes.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取YYYY格式
|
||||
* @return
|
||||
*/
|
||||
public static String getYear() {
|
||||
return sdfYear.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取YYYY-MM-DD格式
|
||||
* @return
|
||||
*/
|
||||
public static String getDay() {
|
||||
return sdfDay.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取YYYYMMDD格式
|
||||
* @return
|
||||
*/
|
||||
public static String getDays(){
|
||||
return sdfDays.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取YYYY-MM-DD HH:mm:ss格式
|
||||
* @return
|
||||
*/
|
||||
public static String getTime() {
|
||||
return sdfTime.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Title: compareDate
|
||||
* @Description: TODO(日期比较,如果s>=e 返回true 否则返回false)
|
||||
* @param s
|
||||
* @param e
|
||||
* @return boolean
|
||||
* @throws
|
||||
* @author fh
|
||||
*/
|
||||
public static boolean compareDate(String s, String e) {
|
||||
if(fomatDate(s)==null||fomatDate(e)==null){
|
||||
return false;
|
||||
}
|
||||
return fomatDate(s).getTime() >=fomatDate(e).getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
* @return
|
||||
*/
|
||||
public static Date fomatDate(String date) {
|
||||
DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
|
||||
try {
|
||||
return fmt.parse(date);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验日期是否合法
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValidDate(String s) {
|
||||
DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
|
||||
try {
|
||||
fmt.parse(s);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false; // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param startTime
|
||||
* @param endTime
|
||||
* @return
|
||||
*/
|
||||
public static int getDiffYear(String startTime,String endTime) {
|
||||
DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
|
||||
try {
|
||||
int years=(int) (((fmt.parse(endTime).getTime()-fmt.parse(startTime).getTime())/ (1000 * 60 * 60 * 24))/365);
|
||||
return years;
|
||||
} catch (Exception e) {
|
||||
return 0; // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <li>功能描述:时间相减得到天数
|
||||
* @param beginDateStr
|
||||
* @param endDateStr
|
||||
* @return
|
||||
* long
|
||||
* @author Administrator
|
||||
*/
|
||||
public static long getDaySub(String beginDateStr,String endDateStr){
|
||||
long day=0;
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Date beginDate = null;
|
||||
Date endDate = null;
|
||||
try {
|
||||
beginDate = format.parse(beginDateStr);
|
||||
endDate= format.parse(endDateStr);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
day=(endDate.getTime()-beginDate.getTime())/(24*60*60*1000);
|
||||
//System.out.println("相隔的天数="+day);
|
||||
return day;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到n天之后的日期
|
||||
* @param days
|
||||
* @return
|
||||
*/
|
||||
public static String getAfterDayDate(String days) {
|
||||
int daysInt = Integer.parseInt(days);
|
||||
Calendar canlendar = Calendar.getInstance(); // java.util包
|
||||
canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
|
||||
Date date = canlendar.getTime();
|
||||
SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String dateStr = sdfd.format(date);
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到n天之后是周几
|
||||
* @param days
|
||||
* @return
|
||||
*/
|
||||
public static String getAfterDayWeek(String days) {
|
||||
int daysInt = Integer.parseInt(days);
|
||||
Calendar canlendar = Calendar.getInstance(); // java.util包
|
||||
canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
|
||||
Date date = canlendar.getTime();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("E");
|
||||
String dateStr = sdf.format(date);
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照yyyy-MM-dd HH:mm:ss的格式,日期转字符串
|
||||
* @param date
|
||||
* @return yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String date2Str(Date date){
|
||||
return date2Str(date,"yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照yyyy-MM-dd HH:mm:ss的格式,字符串转日期
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static Date str2Date(String date){
|
||||
if(StringUtils.isNotBlank(date)){
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
try {
|
||||
return sdf.parse(date);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new Date();
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 把时间根据时、分、秒转换为时间段
|
||||
* @param StrDate
|
||||
*/
|
||||
public static String getTimes(String StrDate){
|
||||
String resultTimes = "";
|
||||
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
Date now;
|
||||
try {
|
||||
now = new Date();
|
||||
Date date=df.parse(StrDate);
|
||||
long times = now.getTime()-date.getTime();
|
||||
long day = times/(24*60*60*1000);
|
||||
long hour = (times/(60*60*1000)-day*24);
|
||||
long min = ((times/(60*1000))-day*24*60-hour*60);
|
||||
long sec = (times/1000-day*24*60*60-hour*60*60-min*60);
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
//sb.append("发表于:");
|
||||
if(hour>0 ){
|
||||
sb.append(hour+"小时前");
|
||||
} else if(min>0){
|
||||
sb.append(min+"分钟前");
|
||||
} else{
|
||||
sb.append(sec+"秒前");
|
||||
}
|
||||
resultTimes = sb.toString();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return resultTimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照参数format的格式,日期转字符串
|
||||
*
|
||||
* @param date
|
||||
* @param format
|
||||
* @return
|
||||
*/
|
||||
public static String date2Str(Date date, String format){
|
||||
if(date!=null){
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(format);
|
||||
return sdf.format(date);
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当年的第一天
|
||||
* @param year
|
||||
* @author zhangyue
|
||||
* @return
|
||||
*/
|
||||
public static String getCurrYearFirst(){
|
||||
Calendar currCal=Calendar.getInstance();
|
||||
int currentYear = currCal.get(Calendar.YEAR);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.clear();
|
||||
calendar.set(Calendar.YEAR, currentYear);
|
||||
Date currYearFirst = calendar.getTime();
|
||||
return sdfDay.format(currYearFirst);
|
||||
}
|
||||
/**
|
||||
* 得到几天前的时间
|
||||
*
|
||||
* @param d
|
||||
* @param day
|
||||
* @return
|
||||
*/
|
||||
public static Date getDateBefore(Date d, int day) {
|
||||
Calendar now = Calendar.getInstance();
|
||||
now.setTime(d);
|
||||
now.set(Calendar.DATE, now.get(Calendar.DATE) - day);
|
||||
return now.getTime();
|
||||
}
|
||||
/**
|
||||
* 获取当年的最后一天
|
||||
* @param year
|
||||
* @author zhangyue
|
||||
* @return
|
||||
*/
|
||||
public static String getCurrYearLast(){
|
||||
Calendar currCal=Calendar.getInstance();
|
||||
int currentYear = currCal.get(Calendar.YEAR);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.clear();
|
||||
calendar.set(Calendar.YEAR, currentYear);
|
||||
calendar.roll(Calendar.DAY_OF_YEAR, -1);
|
||||
Date currYearLast = calendar.getTime();
|
||||
return sdfDay.format(currYearLast);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前季度第一天
|
||||
* @author zhangyue
|
||||
* @return
|
||||
*/
|
||||
public static String quarterStart() {
|
||||
Date dBegin = new Date();
|
||||
Calendar calBegin = Calendar.getInstance();
|
||||
calBegin.setTime(dBegin);
|
||||
int remainder = calBegin.get(Calendar.MONTH) % 3;
|
||||
int month = remainder != 0 ? calBegin.get(Calendar.MONTH) - remainder: calBegin.get(Calendar.MONTH);
|
||||
|
||||
calBegin.set(Calendar.MONTH, month);
|
||||
calBegin.set(Calendar.DAY_OF_MONTH, calBegin.getActualMinimum(Calendar.DAY_OF_MONTH));
|
||||
|
||||
calBegin.setTime(calBegin.getTime());
|
||||
return sdfDay.format(calBegin.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前季度最后一天
|
||||
* @author zhangyue
|
||||
* @return
|
||||
*/
|
||||
public static String quarterEnd() {
|
||||
Date dEnd = new Date();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(dEnd);
|
||||
int remainder = (calendar.get(Calendar.MONTH) + 1) % 3;
|
||||
int month = remainder != 0 ? calendar.get(Calendar.MONTH) + (3 - remainder) : calendar.get(Calendar.MONTH);
|
||||
calendar.set(Calendar.MONTH, month);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
calendar.setTime(calendar.getTime());
|
||||
return sdfDay.format(calendar.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本月第一天日期
|
||||
* @return
|
||||
*/
|
||||
public static String getMonthFirstDay() {
|
||||
Calendar thisMonthFirstDateCal = Calendar.getInstance();
|
||||
thisMonthFirstDateCal.set(Calendar.DAY_OF_MONTH, 1);
|
||||
String thisMonthFirstTime = sdfDay.format(thisMonthFirstDateCal.getTime());
|
||||
return thisMonthFirstTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本月最后一天日期
|
||||
* @return
|
||||
*/
|
||||
public static String getMonthEndDay() {
|
||||
Calendar thisMonthEndDateCal = Calendar.getInstance();
|
||||
thisMonthEndDateCal.set(Calendar.DAY_OF_MONTH, thisMonthEndDateCal.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
String thisMonthEndTime = sdfDay.format(thisMonthEndDateCal.getTime());
|
||||
return thisMonthEndTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取近多少天
|
||||
* @param date 日期
|
||||
* @param days 近几天(负数.日期以前几天;正数.日期以后几天)
|
||||
* @return
|
||||
*/
|
||||
public static List<String> getNearDays(Date date, int days) {
|
||||
Calendar currentDate = Calendar.getInstance();
|
||||
currentDate.setTime(date);
|
||||
Calendar nearDate = Calendar.getInstance();
|
||||
nearDate.setTime(date);
|
||||
nearDate.add(Calendar.DATE, days);
|
||||
List<String> result = new ArrayList<String>();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");// 格式化为年月
|
||||
if (currentDate.before(nearDate)) {
|
||||
Calendar curr = currentDate;
|
||||
nearDate.set(nearDate.get(Calendar.YEAR), nearDate.get(Calendar.MONTH), nearDate.get(Calendar.DATE));
|
||||
while (curr.before(nearDate)) {
|
||||
result.add(sdf.format(curr.getTime()));
|
||||
curr.add(Calendar.DATE, 1);
|
||||
}
|
||||
} else {
|
||||
Calendar curr = nearDate;
|
||||
currentDate.set(currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE) + 1);
|
||||
while (curr.before(currentDate)) {
|
||||
result.add(sdf.format(curr.getTime()));
|
||||
curr.add(Calendar.DATE, 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* utc时间转cst时间
|
||||
* @param UTCStr
|
||||
* @return
|
||||
*/
|
||||
public static String parseUTCToCST(String UTCStr){
|
||||
Date date = null;
|
||||
String cstTime = null;
|
||||
Calendar calendar = null;
|
||||
try {
|
||||
date = utsTime.parse(UTCStr);
|
||||
calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
//注意这里,需要+8小时
|
||||
calendar.set(Calendar.HOUR,calendar.get(Calendar.HOUR)+8);
|
||||
cstTime = sdfDay.format(calendar.getTime());
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return cstTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* cst时间转utc时间
|
||||
* @param CSTStr
|
||||
* @return
|
||||
*/
|
||||
public static String parseCSTToUTC(String CSTStr){
|
||||
Date date = null;
|
||||
String cstTime = null;
|
||||
Calendar calendar = null;
|
||||
try {
|
||||
date = sdfTime.parse(CSTStr);
|
||||
calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
//注意这里,需要+8小时
|
||||
calendar.set(Calendar.HOUR,calendar.get(Calendar.HOUR)-8);
|
||||
cstTime = utsTime.format(calendar.getTime());
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return cstTime;
|
||||
}
|
||||
|
||||
public static String secondsToTimeHHMM(String seconds) {
|
||||
int intValue = (int) Math.floor(Double.parseDouble(seconds));
|
||||
// Date date = new Date(intValue * 1000L); // 秒转毫秒
|
||||
// SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
|
||||
// return sdf.format(date);
|
||||
|
||||
int minutes = (int) TimeUnit.SECONDS.toMinutes(intValue);
|
||||
intValue -= TimeUnit.MINUTES.toSeconds(minutes);
|
||||
return String.format("%02d:%02d", minutes, intValue);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(secondsToTimeHHMM("3068.07"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
|
||||
|
||||
package com.zcloud.common.utils;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 日期处理
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class DateUtils {
|
||||
/** 时间格式(yyyy-MM-dd) */
|
||||
public final static String DATE_PATTERN = "yyyy-MM-dd";
|
||||
/** 时间格式(yyyy-MM-dd HH:mm:ss) */
|
||||
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
/**
|
||||
* 日期格式化 日期格式为:yyyy-MM-dd
|
||||
* @param date 日期
|
||||
* @return 返回yyyy-MM-dd格式日期
|
||||
*/
|
||||
public static String format(Date date) {
|
||||
return format(date, DATE_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式化 日期格式为:yyyy-MM-dd
|
||||
* @param date 日期
|
||||
* @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN
|
||||
* @return 返回yyyy-MM-dd格式日期
|
||||
*/
|
||||
public static String format(Date date, String pattern) {
|
||||
if(date != null){
|
||||
SimpleDateFormat df = new SimpleDateFormat(pattern);
|
||||
return df.format(date);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转换成日期
|
||||
* @param strDate 日期字符串
|
||||
* @param pattern 日期的格式,如:DateUtils.DATE_TIME_PATTERN
|
||||
*/
|
||||
public static Date stringToDate(String strDate, String pattern) {
|
||||
if (StringUtils.isBlank(strDate)){
|
||||
return null;
|
||||
}
|
||||
|
||||
DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
|
||||
return fmt.parseLocalDateTime(strDate).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据周数,获取开始日期、结束日期
|
||||
* @param week 周期 0本周,-1上周,-2上上周,1下周,2下下周
|
||||
* @return 返回date[0]开始日期、date[1]结束日期
|
||||
*/
|
||||
public static Date[] getWeekStartAndEnd(int week) {
|
||||
DateTime dateTime = new DateTime();
|
||||
LocalDate date = new LocalDate(dateTime.plusWeeks(week));
|
||||
|
||||
date = date.dayOfWeek().withMinimumValue();
|
||||
Date beginDate = date.toDate();
|
||||
Date endDate = date.plusDays(6).toDate();
|
||||
return new Date[]{beginDate, endDate};
|
||||
}
|
||||
|
||||
/**
|
||||
* 对日期的【秒】进行加/减
|
||||
*
|
||||
* @param date 日期
|
||||
* @param seconds 秒数,负数为减
|
||||
* @return 加/减几秒后的日期
|
||||
*/
|
||||
public static Date addDateSeconds(Date date, int seconds) {
|
||||
DateTime dateTime = new DateTime(date);
|
||||
return dateTime.plusSeconds(seconds).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对日期的【分钟】进行加/减
|
||||
*
|
||||
* @param date 日期
|
||||
* @param minutes 分钟数,负数为减
|
||||
* @return 加/减几分钟后的日期
|
||||
*/
|
||||
public static Date addDateMinutes(Date date, int minutes) {
|
||||
DateTime dateTime = new DateTime(date);
|
||||
return dateTime.plusMinutes(minutes).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对日期的【小时】进行加/减
|
||||
*
|
||||
* @param date 日期
|
||||
* @param hours 小时数,负数为减
|
||||
* @return 加/减几小时后的日期
|
||||
*/
|
||||
public static Date addDateHours(Date date, int hours) {
|
||||
DateTime dateTime = new DateTime(date);
|
||||
return dateTime.plusHours(hours).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对日期的【天】进行加/减
|
||||
*
|
||||
* @param date 日期
|
||||
* @param days 天数,负数为减
|
||||
* @return 加/减几天后的日期
|
||||
*/
|
||||
public static Date addDateDays(Date date, int days) {
|
||||
DateTime dateTime = new DateTime(date);
|
||||
return dateTime.plusDays(days).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对日期的【周】进行加/减
|
||||
*
|
||||
* @param date 日期
|
||||
* @param weeks 周数,负数为减
|
||||
* @return 加/减几周后的日期
|
||||
*/
|
||||
public static Date addDateWeeks(Date date, int weeks) {
|
||||
DateTime dateTime = new DateTime(date);
|
||||
return dateTime.plusWeeks(weeks).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对日期的【月】进行加/减
|
||||
*
|
||||
* @param date 日期
|
||||
* @param months 月数,负数为减
|
||||
* @return 加/减几月后的日期
|
||||
*/
|
||||
public static Date addDateMonths(Date date, int months) {
|
||||
DateTime dateTime = new DateTime(date);
|
||||
return dateTime.plusMonths(months).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对日期的【年】进行加/减
|
||||
*
|
||||
* @param date 日期
|
||||
* @param years 年数,负数为减
|
||||
* @return 加/减几年后的日期
|
||||
*/
|
||||
public static Date addDateYears(Date date, int years) {
|
||||
DateTime dateTime = new DateTime(date);
|
||||
return dateTime.plusYears(years).toDate();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* excel工具类
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class ExcelUtils {
|
||||
|
||||
/**
|
||||
* Excel导出
|
||||
*
|
||||
* @param response response
|
||||
* @param fileName 文件名
|
||||
* @param list 数据List
|
||||
* @param pojoClass 对象Class
|
||||
*/
|
||||
public static void exportExcel(HttpServletResponse response, String fileName, Collection<?> list,
|
||||
Class<?> pojoClass) throws IOException {
|
||||
if(StringUtils.isBlank(fileName)){
|
||||
//当前日期
|
||||
fileName = DateUtils.format(new Date());
|
||||
}
|
||||
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), pojoClass, list);
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setHeader("content-Type", "application/vnd.ms-excel");
|
||||
response.setHeader("Content-Disposition",
|
||||
"attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
workbook.write(out);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Excel导出,先sourceList转换成List<targetClass>,再导出
|
||||
*
|
||||
* @param response response
|
||||
* @param fileName 文件名
|
||||
* @param sourceList 原数据List
|
||||
* @param targetClass 目标对象Class
|
||||
*/
|
||||
public static void exportExcelToTarget(HttpServletResponse response, String fileName, Collection<?> sourceList,
|
||||
Class<?> targetClass) throws Exception {
|
||||
List targetList = new ArrayList<>(sourceList.size());
|
||||
for(Object source : sourceList){
|
||||
Object target = targetClass.newInstance();
|
||||
BeanUtils.copyProperties(source, target);
|
||||
targetList.add(target);
|
||||
}
|
||||
|
||||
exportExcel(response, fileName, targetList, targetClass);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.zcloud.common.exception.ZException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* 说明:上传文件
|
||||
|
||||
|
||||
*/
|
||||
public class FileUpload {
|
||||
|
||||
/**上传文件
|
||||
* @param file //文件对象
|
||||
* @param filePath //上传路径
|
||||
* @param fileName //文件名
|
||||
* @return 文件名
|
||||
*/
|
||||
public static String fileUp(MultipartFile file, String filePath, String fileName) throws IOException {
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
throw new ZException("课件保存到本地失败");
|
||||
}
|
||||
return fileName+extName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写文件到当前目录的upload目录中
|
||||
* @param in
|
||||
* @param fileName
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String copyFile(InputStream in, String dir, String realName)
|
||||
throws IOException {
|
||||
File file = mkdirsmy(dir,realName);
|
||||
FileUtils.copyInputStreamToFile(in, file);
|
||||
in.close();
|
||||
return realName;
|
||||
}
|
||||
|
||||
|
||||
/**判断路径是否存在,否:创建此路径
|
||||
* @param dir 文件路径
|
||||
* @param realName 文件名
|
||||
* @throws IOException
|
||||
*/
|
||||
public static File mkdirsmy(String dir, String realName) throws IOException{
|
||||
File file = new File(dir, realName);
|
||||
if (!file.exists()) {
|
||||
if (!file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
file.createNewFile();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
* @param file //文件对象
|
||||
*/
|
||||
public static void fileDelete(File file){
|
||||
if (file != null && file.exists()) { // 文件存在
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**下载网络图片上传到服务器上
|
||||
* @param httpUrl 图片网络地址
|
||||
* @param filePath 图片保存路径
|
||||
* @param myFileName 图片文件名(null时用网络图片原名)
|
||||
* @return 返回图片名称
|
||||
*/
|
||||
public static String getHtmlPicture(String httpUrl, String filePath , String myFileName) {
|
||||
|
||||
URL url; //定义URL对象url
|
||||
BufferedInputStream in; //定义输入字节缓冲流对象in
|
||||
FileOutputStream file; //定义文件输出流对象file
|
||||
try {
|
||||
String fileName = null == myFileName?httpUrl.substring(httpUrl.lastIndexOf("/")).replace("/", ""):myFileName; //图片文件名(null时用网络图片原名)
|
||||
url = new URL(httpUrl); //初始化url对象
|
||||
in = new BufferedInputStream(url.openStream()); //初始化in对象,也就是获得url字节流
|
||||
//file = new FileOutputStream(new File(filePath +"\\"+ fileName));
|
||||
file = new FileOutputStream(mkdirsmy(filePath,fileName));
|
||||
int t;
|
||||
while ((t = in.read()) != -1) {
|
||||
file.write(t);
|
||||
}
|
||||
file.close();
|
||||
in.close();
|
||||
return fileName;
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.aliyun.oss.ClientException;
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
import com.aliyun.oss.OSSException;
|
||||
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@Component
|
||||
public class FileUploadUtil {
|
||||
|
||||
private static String endpoint = "https://oss-cn-zhangjiakou.aliyuncs.com";
|
||||
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
|
||||
private static String accessKeyId = "LTAI5tK134ZzXPEwykAdpVn2";
|
||||
private static String accessKeySecret = "XCEMY8FG52cXImFMeIiH4tDJ9BIN3N";
|
||||
// 填写Bucket名称。
|
||||
private static String bucketName = "qyag";
|
||||
|
||||
public static void sshSftp(MultipartFile file, String fileName, String path){
|
||||
String objectName = "KjkFile" + path + "/" + fileName;
|
||||
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
|
||||
// 创建OSSClient实例。
|
||||
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
|
||||
|
||||
try {
|
||||
|
||||
// 创建PutObject请求。
|
||||
ossClient.putObject(bucketName, objectName, file.getInputStream());
|
||||
|
||||
// 创建PutObjectRequest对象。
|
||||
// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
|
||||
// ObjectMetadata metadata = new ObjectMetadata();
|
||||
// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
|
||||
// metadata.setObjectAcl(CannedAccessControlList.Private);
|
||||
// putObjectRequest.setMetadata(metadata);
|
||||
|
||||
// 上传文件。
|
||||
} catch (OSSException oe) {
|
||||
System.out.println("Caught an OSSException, which means your request made it to OSS, "
|
||||
+ "but was rejected with an error response for some reason.");
|
||||
System.out.println("Error Message:" + oe.getErrorMessage());
|
||||
System.out.println("Error Code:" + oe.getErrorCode());
|
||||
System.out.println("Request ID:" + oe.getRequestId());
|
||||
System.out.println("Host ID:" + oe.getHostId());
|
||||
} catch (ClientException ce) {
|
||||
System.out.println("Caught an ClientException, which means the client encountered "
|
||||
+ "a serious internal problem while trying to communicate with OSS, "
|
||||
+ "such as not being able to access the network.");
|
||||
System.out.println("Error Message:" + ce.getMessage());
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error Message:" + e.getMessage());
|
||||
} finally {
|
||||
if (ossClient != null) {
|
||||
ossClient.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*/
|
||||
public static void deleteFile(String directoryFile) {
|
||||
|
||||
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
|
||||
|
||||
try {
|
||||
// 删除文件或目录。如果要删除目录,目录必须为空。
|
||||
ossClient.deleteObject(bucketName, "TuyouFile" + directoryFile);
|
||||
} catch (OSSException oe) {
|
||||
System.out.println("Caught an OSSException, which means your request made it to OSS, "
|
||||
+ "but was rejected with an error response for some reason.");
|
||||
System.out.println("Error Message:" + oe.getErrorMessage());
|
||||
System.out.println("Error Code:" + oe.getErrorCode());
|
||||
System.out.println("Request ID:" + oe.getRequestId());
|
||||
System.out.println("Host ID:" + oe.getHostId());
|
||||
} catch (ClientException ce) {
|
||||
System.out.println("Caught an ClientException, which means the client encountered "
|
||||
+ "a serious internal problem while trying to communicate with OSS, "
|
||||
+ "such as not being able to access the network.");
|
||||
System.out.println("Error Message:" + ce.getMessage());
|
||||
} finally {
|
||||
if (ossClient != null) {
|
||||
ossClient.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class HttpContextUtils {
|
||||
|
||||
public static HttpServletRequest getHttpServletRequest() {
|
||||
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
}
|
||||
|
||||
public static String getDomain(){
|
||||
HttpServletRequest request = getHttpServletRequest();
|
||||
StringBuffer url = request.getRequestURL();
|
||||
return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
|
||||
}
|
||||
|
||||
public static String getOrigin(){
|
||||
HttpServletRequest request = getHttpServletRequest();
|
||||
return request.getHeader("Origin");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
/**
|
||||
* description: http请求工具类
|
||||
*
|
||||
* @date 2022-07-01
|
||||
*/
|
||||
public class HttpRequestUtil {
|
||||
|
||||
public static String sendRequest(String urlParam) throws Exception {
|
||||
InputStream inputStream = null;
|
||||
BufferedReader buffer = null;
|
||||
try {
|
||||
URL url = new URL(urlParam);
|
||||
URLConnection con = url.openConnection();
|
||||
//设置请求需要返回的数据类型和字符集类型
|
||||
con.setRequestProperty("Content-Type", "application/json;charset=GBK");
|
||||
//允许写出
|
||||
con.setDoOutput(true);
|
||||
//允许读入
|
||||
con.setDoInput(true);
|
||||
//不使用缓存
|
||||
con.setUseCaches(false);
|
||||
//得到响应流
|
||||
inputStream = con.getInputStream();
|
||||
//将响应流转换成字符串
|
||||
StringBuffer resultBuffer = new StringBuffer();
|
||||
String line;
|
||||
buffer = new BufferedReader(new InputStreamReader(inputStream, "GBK"));
|
||||
while ((line = buffer.readLine()) != null) {
|
||||
resultBuffer.append(line);
|
||||
}
|
||||
return resultBuffer.toString();
|
||||
} catch (Exception e) {
|
||||
buffer.close();
|
||||
inputStream.close();
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getRestInformation(HttpServletRequest request) throws Exception {
|
||||
return getRestInformation(request,String.class);
|
||||
}
|
||||
|
||||
public static <T> T getRestInformation(HttpServletRequest request, Class<T> clazz) throws Exception {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
|
||||
StringBuffer data = new StringBuffer();
|
||||
String line = null;
|
||||
reader = request.getReader();
|
||||
while (null != (line = reader.readLine())) data.append(line);
|
||||
reader.close();
|
||||
T result = JSONObject.parseObject(data.toString(), clazz);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("解析请求报文出错");
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Http get请求
|
||||
* @param httpUrl 连接
|
||||
* @return 响应数据
|
||||
*/
|
||||
public static String doGet(String httpUrl) throws Exception{
|
||||
//链接
|
||||
HttpURLConnection connection = null;
|
||||
InputStream is = null;
|
||||
BufferedReader br = null;
|
||||
StringBuffer result = new StringBuffer();
|
||||
try {
|
||||
//创建连接
|
||||
URL url = new URL(httpUrl);
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
//设置请求方式
|
||||
connection.setRequestMethod("GET");
|
||||
//设置连接超时时间
|
||||
connection.setReadTimeout(15000);
|
||||
//开始连接
|
||||
connection.connect();
|
||||
//获取响应数据
|
||||
if (connection.getResponseCode() == 200) {
|
||||
//获取返回的数据
|
||||
is = connection.getInputStream();
|
||||
if (null != is) {
|
||||
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
|
||||
String temp = null;
|
||||
while (null != (temp = br.readLine())) {
|
||||
result.append(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (null != br) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (null != is) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
//关闭远程连接
|
||||
connection.disconnect();
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Http post请求
|
||||
* @param httpUrl 连接
|
||||
* @param param 参数
|
||||
* @return
|
||||
*/
|
||||
public static String doPost(String httpUrl, @Nullable String param) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
//连接
|
||||
HttpURLConnection connection = null;
|
||||
OutputStream os = null;
|
||||
InputStream is = null;
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
//创建连接对象
|
||||
URL url = new URL(httpUrl);
|
||||
//创建连接
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
//设置请求方法
|
||||
connection.setRequestMethod("POST");
|
||||
//设置连接超时时间
|
||||
connection.setConnectTimeout(60000);
|
||||
//设置读取超时时间
|
||||
connection.setReadTimeout(1000 * 60 * 20);
|
||||
//DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个
|
||||
//设置是否可读取
|
||||
connection.setDoOutput(true);
|
||||
connection.setDoInput(true);
|
||||
//设置通用的请求属性
|
||||
// connection.setRequestProperty("accept", "*/*");
|
||||
// connection.setRequestProperty("connection", "Keep-Alive");
|
||||
// connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
|
||||
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
||||
//拼装参数
|
||||
if (null != param && !param.equals("")) {
|
||||
//设置参数
|
||||
os = connection.getOutputStream();
|
||||
//拼装参数
|
||||
os.write(param.getBytes());
|
||||
}
|
||||
//设置权限
|
||||
//设置请求头等
|
||||
//开启连接
|
||||
//connection.connect();
|
||||
//读取响应
|
||||
if (connection.getResponseCode() == 200) {
|
||||
is = connection.getInputStream();
|
||||
if (null != is) {
|
||||
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
|
||||
String temp = null;
|
||||
while (null != (temp = br.readLine())) {
|
||||
result.append(temp);
|
||||
result.append("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
//关闭连接
|
||||
if(br!=null){
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if(os!=null){
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if(is!=null){
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
//关闭连接
|
||||
connection.disconnect();
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
|
||||
package com.zcloud.common.utils;
|
||||
|
||||
import com.alibaba.druid.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* IP地址
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class IPUtils {
|
||||
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
|
||||
|
||||
/**
|
||||
* 获取IP地址
|
||||
*
|
||||
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
|
||||
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
|
||||
*/
|
||||
public static String getIpAddr(HttpServletRequest request) {
|
||||
String ip = null;
|
||||
try {
|
||||
ip = request.getHeader("x-forwarded-for");
|
||||
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("HTTP_CLIENT_IP");
|
||||
}
|
||||
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
|
||||
}
|
||||
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("IPUtils ERROR ", e);
|
||||
}
|
||||
|
||||
// //使用代理,则获取第一个IP地址
|
||||
// if(StringUtils.isEmpty(ip) && ip.length() > 15) {
|
||||
// if(ip.indexOf(",") > 0) {
|
||||
// ip = ip.substring(0, ip.indexOf(","));
|
||||
// }
|
||||
// }
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* 说明:MD5处理
|
||||
|
||||
|
||||
*/
|
||||
public class MD5 {
|
||||
|
||||
public static String md5(String str) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.update(str.getBytes());
|
||||
byte b[] = md.digest();
|
||||
|
||||
int i;
|
||||
|
||||
StringBuffer buf = new StringBuffer("");
|
||||
for (int offset = 0; offset < b.length; offset++) {
|
||||
i = b[offset];
|
||||
if (i < 0)
|
||||
i += 256;
|
||||
if (i < 16)
|
||||
buf.append("0");
|
||||
buf.append(Integer.toHexString(i));
|
||||
}
|
||||
str = buf.toString();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
return str;
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
System.out.println(md5("62a48def61194d4382d3d0aeb800a050" + "zxdk.qhdsafety.com"));
|
||||
// System.out.println(md5("mj1"));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import ws.schild.jave.MultimediaInfo;
|
||||
import ws.schild.jave.MultimediaObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/10/20 10:10
|
||||
*/
|
||||
public class MP4Util {
|
||||
public static String getMP4Time(File video) {
|
||||
// 视频时长
|
||||
String time = "0";
|
||||
try {
|
||||
MultimediaObject media = new MultimediaObject(video);
|
||||
MultimediaInfo info = media.getInfo();
|
||||
// 时长,毫秒级
|
||||
long duration = info.getDuration();
|
||||
// 毫秒级时长转化为秒
|
||||
BigDecimal bigDecimal1 = new BigDecimal(duration);
|
||||
BigDecimal bigDecimal2 = new BigDecimal(1000);
|
||||
// 四舍五入,只保留整数
|
||||
time = bigDecimal1.divide(bigDecimal2, 0, RoundingMode.HALF_UP).toString();
|
||||
// // 获取媒体视频对象
|
||||
// VideoInfo video = info.getVideo();
|
||||
// // 码率
|
||||
// int bitRate = video.getBitRate();
|
||||
// // 帧率
|
||||
// float frameRate = video.getFrameRate();
|
||||
// // 分辨率-高
|
||||
// int height = video.getSize().getHeight();
|
||||
// // 分辨率-宽
|
||||
// int width = video.getSize().getWidth();
|
||||
// // 视频解码器名称
|
||||
// String decoder = video.getDecoder();
|
||||
} catch (Exception e) {
|
||||
e.getMessage();
|
||||
}
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
|
||||
package com.zcloud.common.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
/**
|
||||
* Map工具类
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class MapUtils extends HashMap<String, Object> {
|
||||
|
||||
@Override
|
||||
public MapUtils put(String key, Object value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
package com.zcloud.util;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* 说明:从EXCEL导入到系统
|
||||
|
||||
|
||||
*/
|
||||
public class ObjectExcelRead {
|
||||
|
||||
/**
|
||||
* @param filepath //文件路径
|
||||
* @param filename //文件名
|
||||
* @param startrow //开始行号
|
||||
* @param startcol //开始列号
|
||||
* @param sheetnum //sheet
|
||||
* @return list
|
||||
*/
|
||||
public static List<Map<String,String>> readExcel(File target, int startrow, int startcol, int sheetnum) {
|
||||
List<Map<String,String>> varList = new ArrayList<Map<String,String>> ();
|
||||
|
||||
try {
|
||||
FileInputStream fi = new FileInputStream(target);
|
||||
HSSFWorkbook wb = new HSSFWorkbook(fi);
|
||||
HSSFSheet sheet = wb.getSheetAt(sheetnum); //sheet 从0开始
|
||||
// int rowNum = getExcelRealRow(sheet) ; //取得最后一行的行号
|
||||
|
||||
for (int i = startrow; i <= sheet.getLastRowNum(); i++) { //行循环开始
|
||||
Map<String,String> varMap = new HashMap<String, String>();
|
||||
HSSFRow row = sheet.getRow(i); //行
|
||||
boolean isEmpty = true;
|
||||
if (row == null) {
|
||||
continue;
|
||||
}
|
||||
for (Cell c : row) {
|
||||
if (c.getCellType() != CellType.BLANK) {
|
||||
isEmpty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isEmpty){
|
||||
continue;
|
||||
}
|
||||
varMap.put("rowNum", String.valueOf(row.getRowNum()+1));
|
||||
int cellNum = row.getLastCellNum(); //每行的最后一个单元格位置
|
||||
|
||||
for (int j = startcol; j < cellNum; j++) { //列循环开始
|
||||
|
||||
HSSFCell cell = row.getCell(Short.parseShort(j + ""));
|
||||
String cellValue = null;
|
||||
if (null != cell) {
|
||||
switch (cell.getCellType().getCode()) { // 判断excel单元格内容的格式,并对其进行转换,以便插入数据库
|
||||
case 0:
|
||||
BigDecimal bigDecimal = new BigDecimal(cell.getNumericCellValue());
|
||||
cellValue = bigDecimal.toPlainString();
|
||||
// cellValue = String.valueOf((int) cell.getNumericCellValue());
|
||||
break;
|
||||
case 1:
|
||||
cellValue = cell.getStringCellValue();
|
||||
break;
|
||||
case 2:
|
||||
cellValue = cell.getNumericCellValue() + "";
|
||||
// cellValue = String.valueOf(cell.getDateCellValue());
|
||||
break;
|
||||
case 3:
|
||||
cellValue = "";
|
||||
break;
|
||||
case 4:
|
||||
cellValue = String.valueOf(cell.getBooleanCellValue());
|
||||
break;
|
||||
case 5:
|
||||
cellValue = String.valueOf(cell.getErrorCellValue());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cellValue = "";
|
||||
}
|
||||
varMap.put("var"+j, cellValue);
|
||||
|
||||
}
|
||||
varList.add(varMap);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return varList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取excel表格的真实行数
|
||||
* @param sheet excel文件的工作簿的名称
|
||||
* @return
|
||||
*/
|
||||
public static int getExcelRealRow(HSSFSheet sheet) {
|
||||
boolean flag = false;
|
||||
for (int i = 1; i <= sheet.getLastRowNum(); ) {
|
||||
HSSFRow r = sheet.getRow(i);
|
||||
if (r == null) {
|
||||
// 如果是空行(即没有任何数据、格式),直接把它以下的数据往上移动
|
||||
sheet.shiftRows(i + 1, sheet.getLastRowNum(), -1);
|
||||
continue;
|
||||
}
|
||||
flag = false;
|
||||
for (Cell c : r) {
|
||||
if (c.getCellType() != CellType.BLANK) {
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
i++;
|
||||
continue;
|
||||
} else {
|
||||
// 如果是空白行(即可能没有数据,但是有一定格式)
|
||||
if (i == sheet.getLastRowNum())// 如果到了最后一行,直接将那一行remove掉
|
||||
sheet.removeRow(r);
|
||||
else//如果还没到最后一行,则数据往上移一行
|
||||
sheet.shiftRows(i + 1, sheet.getLastRowNum(), -1);
|
||||
}
|
||||
}
|
||||
return sheet.getLastRowNum();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
public class OrderUtils {
|
||||
|
||||
// 根据商品类型获取前缀
|
||||
private static String getPrefix(String goodsType) {
|
||||
if ("0".equals(goodsType)) {
|
||||
return "TY_"+ String.valueOf(Math.abs("sucai".hashCode()));
|
||||
} else if ("1".equals(goodsType)) {
|
||||
return "TY_" + String.valueOf(Math.abs("kecheng".hashCode()));
|
||||
}
|
||||
throw new IllegalArgumentException("未知的商品类型");
|
||||
}
|
||||
|
||||
// 生成时间戳字符串
|
||||
private static String getTimeStamp() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
return sdf.format(new Date());
|
||||
}
|
||||
|
||||
// 生成随机字符串(用于userId的hash)
|
||||
private static String getRandomHash(String userId) {
|
||||
return String.valueOf(Math.abs(userId.hashCode()));
|
||||
}
|
||||
|
||||
// 组合所有部分生成订单编号
|
||||
public static String generateOrderNumber(String userId) {
|
||||
// String prefix = getPrefix(goodsType);
|
||||
String prefix = "TY_";
|
||||
String timeStamp = getTimeStamp();
|
||||
String userHash = getRandomHash(userId);
|
||||
return prefix + userHash + timeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
|
||||
|
||||
package com.zcloud.common.utils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页工具类
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class PageUtils implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 总记录数
|
||||
*/
|
||||
private int totalCount;
|
||||
/**
|
||||
* 每页记录数
|
||||
*/
|
||||
private int pageSize;
|
||||
/**
|
||||
* 总页数
|
||||
*/
|
||||
private int totalPage;
|
||||
/**
|
||||
* 当前页数
|
||||
*/
|
||||
private int currPage;
|
||||
/**
|
||||
* 列表数据
|
||||
*/
|
||||
private List<?> list;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
* @param list 列表数据
|
||||
* @param totalCount 总记录数
|
||||
* @param pageSize 每页记录数
|
||||
* @param currPage 当前页数
|
||||
*/
|
||||
public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
|
||||
this.list = list;
|
||||
this.totalCount = totalCount;
|
||||
this.pageSize = pageSize;
|
||||
this.currPage = currPage;
|
||||
this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public PageUtils(IPage<?> page) {
|
||||
this.list = page.getRecords();
|
||||
this.totalCount = (int)page.getTotal();
|
||||
this.pageSize = (int)page.getSize();
|
||||
this.currPage = (int)page.getCurrent();
|
||||
this.totalPage = (int)page.getPages();
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public void setTotalCount(int totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public int getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(int pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public int getTotalPage() {
|
||||
return totalPage;
|
||||
}
|
||||
|
||||
public void setTotalPage(int totalPage) {
|
||||
this.totalPage = totalPage;
|
||||
}
|
||||
|
||||
public int getCurrPage() {
|
||||
return currPage;
|
||||
}
|
||||
|
||||
public void setCurrPage(int currPage) {
|
||||
this.currPage = currPage;
|
||||
}
|
||||
|
||||
public List<?> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setList(List<?> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 说明:TODO
|
||||
* 作者:wangxuan
|
||||
* 官网:www.zcloudchina.com
|
||||
*/
|
||||
public class PaperTextValid {
|
||||
private static Pattern pattern = Pattern.compile("[0-9]*");
|
||||
|
||||
/**
|
||||
* @Description: errorMsg 错误信息,sheet,行,操作项,单选名,列名,单选多选 ture 或 填空,判断 false
|
||||
* @Author: dearLin
|
||||
* @Date: 2023/3/15/015 9:31
|
||||
* @Param: [java.lang.StringBuilder, int, int, com.zcloud.entity.PageData, java.lang.String[], java.util.HashMap, boolean] [errorMsg, finalI, i, x, choice, column, cOrb]
|
||||
* @Return: void
|
||||
*/
|
||||
public static void checkValid(StringBuilder errorMsg, int sheetNum, Map<Object, Object> x, String[] choice, HashMap<Integer, String> column, boolean cOrb) {
|
||||
|
||||
for (int j = 0; j < choice.length; j++) {
|
||||
String item = (String) x.get("var" + j);
|
||||
|
||||
if (StringUtils.isEmpty(item)) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "不能为空");
|
||||
continue;
|
||||
}
|
||||
// 校验每一项长度不可超过254
|
||||
if (item.length() > 254) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "长度超过254");
|
||||
}
|
||||
// 分值校验
|
||||
if ("分值".equals(column.get(j))) {
|
||||
if (!isNumeric(item)) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "分值只能是小数与整数");
|
||||
}
|
||||
}
|
||||
|
||||
// 单选多选
|
||||
if (cOrb) {
|
||||
if ((j == 7 || j == 8) && item.equals("NO_Label_Type")) {
|
||||
//标签类型
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "未找到,请与数据字典的标签类型对应上");
|
||||
}
|
||||
if ("单选答案".equals(column.get(j))) {
|
||||
//校验答案位数
|
||||
if (item.length() >= 2) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "该题为单选,答案位数不对");
|
||||
}
|
||||
//校验答案是否为 A, B, C, D 之一
|
||||
if (!"A".equals(item) && !"B".equals(item) && !"C".equals(item) && !"D".equals(item)) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "单选答案只能是 A, B, C, D 中的一个");
|
||||
}
|
||||
}
|
||||
if ("多选答案".equals(column.get(j))) {
|
||||
//校验答案位数
|
||||
if (item.length() < 1) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "该题为多选,答案位数不对");
|
||||
}
|
||||
//校验答案是否只包含 A, B, C, D
|
||||
if (!item.matches("[ABCD]+")) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "多选答案只能包含 A, B, C, D 中的一个或多个组合");
|
||||
}
|
||||
//检查多选答案中是否有重复项
|
||||
char[] chars = item.toCharArray();
|
||||
Set<Character> charSet = new HashSet<>();
|
||||
for (char c : chars) {
|
||||
charSet.add(c);
|
||||
}
|
||||
if (charSet.size() != item.length()) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "多选答案中不能有重复选项");
|
||||
}
|
||||
// 对多选答案进行排序
|
||||
List<Character> sortedChars = new ArrayList<>(charSet);
|
||||
Collections.sort(sortedChars);
|
||||
StringBuilder sortedItem = new StringBuilder();
|
||||
for (Character c : sortedChars) {
|
||||
sortedItem.append(c);
|
||||
}
|
||||
// 如果排序后的答案与原答案不同,则添加错误信息
|
||||
if (!sortedItem.toString().equals(item)) {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "多选答案未按 A, B, C, D 顺序排序");
|
||||
}
|
||||
}
|
||||
x.put(choice[j], item);
|
||||
|
||||
} else {
|
||||
// 判断,填空
|
||||
if ((j == 3 || j == 4) && item.equals("NO_Label_Type")) {
|
||||
//标签类型
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "未找到,请与数据字典的标签类型对应上");
|
||||
}
|
||||
if ("判断答案".equals(column.get(j))) {
|
||||
if ("T".equals(item) || "F".equals(item)) {
|
||||
if ("T".equals(item)) {
|
||||
x.put("ANSWER", "A");
|
||||
} else {
|
||||
x.put("ANSWER", "B");
|
||||
}
|
||||
} else {
|
||||
addErrorMsg(errorMsg, sheetNum, (String) x.get("rowNum"), column.get(j), "判断答案只能填写T或F");
|
||||
}
|
||||
} else {
|
||||
x.put(choice[j], item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isNumeric(String str) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return false;
|
||||
}
|
||||
if (str.indexOf(".") > 0) {
|
||||
//判断是否有小数点
|
||||
if (str.indexOf(".") == str.lastIndexOf(".") && str.split("\\.").length == 2) {
|
||||
//判断是否只有一个小数点
|
||||
return pattern.matcher(str.replace(".", "")).matches();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return pattern.matcher(str).matches();
|
||||
}
|
||||
}
|
||||
|
||||
private static void addErrorMsg(StringBuilder errorMsg, int sheetNum, String i, String describe, String reason) {
|
||||
String sheetNAME = "";
|
||||
switch (sheetNum) {
|
||||
case 0:
|
||||
sheetNAME = "单选题";
|
||||
break;
|
||||
case 1:
|
||||
sheetNAME = "多选题";
|
||||
break;
|
||||
case 2:
|
||||
sheetNAME = "判断题";
|
||||
break;
|
||||
case 3:
|
||||
sheetNAME = "填空题";
|
||||
break;
|
||||
}
|
||||
errorMsg.append("[" + sheetNAME + "]sheet:" + "行号" + i + "," + describe + reason + ",导入失败\n");
|
||||
}
|
||||
|
||||
public static boolean betweenOn(LocalDateTime otherStartTime, LocalDateTime otherEndTime, LocalDateTime currStartTime, LocalDateTime currEndTime) {
|
||||
if (otherEndTime.isEqual(currStartTime)) {
|
||||
return true;
|
||||
}
|
||||
if (otherStartTime.isEqual(currEndTime)) {
|
||||
return true;
|
||||
}
|
||||
if (otherStartTime.isAfter(currStartTime)) {
|
||||
// 其他日期段开始日期大于当前日期段开始日日期,那么其他日期段开始日期小于等于当前日期段结束日则为重复
|
||||
return otherStartTime.isBefore(currEndTime);
|
||||
|
||||
} else if (otherStartTime.isBefore(currStartTime)) {
|
||||
// 其他日期段开始日期小于当前开始日期,那么其他日期段结束日期大于等于当前日期段开始日期则为重复
|
||||
return otherEndTime.isAfter(currStartTime);
|
||||
} else {
|
||||
// 其他日期段开始日期=当前日期段开始日期,一定重复
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 说明:路径工具类
|
||||
|
||||
|
||||
*/
|
||||
public class PathUtil {
|
||||
|
||||
/**获取Projectpath
|
||||
* @return
|
||||
*/
|
||||
public static String getProjectpath(){
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
String path = request.getServletContext().getRealPath("/").replaceAll("%20", " ").replaceAll("file:/", "").trim();
|
||||
return path;
|
||||
}
|
||||
|
||||
/**获取Classpath
|
||||
* @return
|
||||
*/
|
||||
public static String getClasspath(){
|
||||
String path = (String.valueOf(Thread.currentThread().getContextClassLoader().getResource(""))).replaceAll("file:/", "").replaceAll("%20", " ").trim();
|
||||
if(path.indexOf(":") != 1){
|
||||
path = File.separator + path;
|
||||
|
||||
}
|
||||
//path = "H:\\"; //当项目以jar、war包运行时,路径改成实际硬盘位置
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.aliyun.oss.event.ProgressEvent;
|
||||
import com.aliyun.oss.event.ProgressEventType;
|
||||
import com.aliyun.vod.upload.impl.VoDProgressListener;
|
||||
|
||||
/**
|
||||
* 上传进度回调方法类
|
||||
* 当您开启上传进度回调时该事件回调才会生效。
|
||||
* OSS分片上传成功或失败均触发相应的回调事件,您可根据业务逻辑处理相应的事件回调。
|
||||
* 当创建音视频信息成功后,此上传进度回调中的videoId为本次上传生成的视频ID,您可以根据视频ID进行音视频管理。
|
||||
* 当创建图片信息成功后,此上传进度回调中的ImageId为本次上传生成的图片ID,您可以根据视频ID进行图片管理。
|
||||
*/
|
||||
|
||||
public class PutObjectProgressListener implements VoDProgressListener {
|
||||
/**
|
||||
* 已成功上传至OSS的字节数
|
||||
*/
|
||||
private long bytesWritten = 0;
|
||||
/**
|
||||
* 原始文件的总字节数
|
||||
*/
|
||||
private long totalBytes = -1;
|
||||
/**
|
||||
* 本次上传成功标记
|
||||
*/
|
||||
private boolean succeed = false;
|
||||
/**
|
||||
* 视频ID
|
||||
*/
|
||||
private String videoId;
|
||||
/**
|
||||
* 图片ID
|
||||
*/
|
||||
private String imageId;
|
||||
|
||||
public void progressChanged(ProgressEvent progressEvent) {
|
||||
long bytes = progressEvent.getBytes();
|
||||
ProgressEventType eventType = progressEvent.getEventType();
|
||||
switch (eventType) {
|
||||
// 开始上传事件
|
||||
case TRANSFER_STARTED_EVENT:
|
||||
if (videoId != null) {
|
||||
System.out.println("Start to upload videoId " + videoId + "......");
|
||||
}
|
||||
if (imageId != null) {
|
||||
System.out.println("Start to upload imageId " + imageId + "......");
|
||||
}
|
||||
break;
|
||||
// 计算待上传文件总大小事件通知,只有调用本地文件方式上传时支持该事件
|
||||
case REQUEST_CONTENT_LENGTH_EVENT:
|
||||
this.totalBytes = bytes;
|
||||
System.out.println(this.totalBytes + "bytes in total will be uploaded to OSS.");
|
||||
break;
|
||||
// 已经上传成功文件大小事件通知(暂不提示)
|
||||
// case REQUEST_BYTE_TRANSFER_EVENT:
|
||||
// this.bytesWritten += bytes;
|
||||
// if (this.totalBytes != -1) {
|
||||
// int percent = (int) (this.bytesWritten * 100.0 / this.totalBytes);
|
||||
// System.out.println(bytes + " bytes have been written at this time, upload progress: " +
|
||||
// percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
|
||||
// } else {
|
||||
// System.out.println(bytes + " bytes have been written at this time, upload sub total : " +
|
||||
// "(" + this.bytesWritten + ")");
|
||||
// }
|
||||
// break;
|
||||
// 文件全部上传成功事件通知
|
||||
case TRANSFER_COMPLETED_EVENT:
|
||||
this.succeed = true;
|
||||
if (videoId != null) {
|
||||
System.out.println("Succeed to upload videoId " + videoId + " , " + this.bytesWritten + " bytes have been transferred in total.");
|
||||
}
|
||||
if (imageId != null) {
|
||||
System.out.println("Succeed to upload imageId " + imageId + " , " + this.bytesWritten + " bytes have been transferred in total.");
|
||||
}
|
||||
break;
|
||||
// 文件上传失败事件通知
|
||||
case TRANSFER_FAILED_EVENT:
|
||||
if (videoId != null) {
|
||||
System.out.println("Failed to upload videoId " + videoId + " , " + this.bytesWritten + " bytes have been transferred.");
|
||||
}
|
||||
if (imageId != null) {
|
||||
System.out.println("Failed to upload imageId " + imageId + " , " + this.bytesWritten + " bytes have been transferred.");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSucceed() {
|
||||
return succeed;
|
||||
}
|
||||
|
||||
public void onVidReady(String videoId) {
|
||||
setVideoId(videoId);
|
||||
}
|
||||
|
||||
public void onImageIdReady(String imageId) {
|
||||
setImageId(imageId);
|
||||
}
|
||||
|
||||
public String getVideoId() {
|
||||
return videoId;
|
||||
}
|
||||
|
||||
public void setVideoId(String videoId) {
|
||||
this.videoId = videoId;
|
||||
}
|
||||
|
||||
public String getImageId() {
|
||||
return imageId;
|
||||
}
|
||||
|
||||
public void setImageId(String imageId) {
|
||||
this.imageId = imageId;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.zcloud.common.xss.SQLFilter;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 查询参数
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class Query<T> {
|
||||
|
||||
public IPage<T> getPage(Map<String, Object> params) {
|
||||
return this.getPage(params, null, false);
|
||||
}
|
||||
|
||||
public IPage<T> getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
|
||||
//分页参数
|
||||
long curPage = 1;
|
||||
long limit = 10;
|
||||
|
||||
if(params.get(Constant.PAGE) != null){
|
||||
curPage = Long.parseLong(params.get(Constant.PAGE).toString());
|
||||
}
|
||||
if(params.get(Constant.LIMIT) != null){
|
||||
limit = Long.parseLong(params.get(Constant.LIMIT).toString());
|
||||
}
|
||||
|
||||
//分页对象
|
||||
Page<T> page = new Page<>(curPage, limit);
|
||||
|
||||
//分页参数
|
||||
params.put(Constant.PAGE, page);
|
||||
|
||||
//排序字段
|
||||
//防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
|
||||
String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER_FIELD));
|
||||
String order = (String)params.get(Constant.ORDER);
|
||||
|
||||
|
||||
//前端字段排序
|
||||
if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){
|
||||
if(Constant.ASC.equalsIgnoreCase(order)) {
|
||||
return page.addOrder(OrderItem.asc(orderField));
|
||||
}else {
|
||||
return page.addOrder(OrderItem.desc(orderField));
|
||||
}
|
||||
}
|
||||
|
||||
//没有排序字段,则不排序
|
||||
if(StringUtils.isBlank(defaultOrderField)){
|
||||
return page;
|
||||
}
|
||||
|
||||
//默认排序
|
||||
if(isAsc) {
|
||||
page.addOrder(OrderItem.asc(defaultOrderField));
|
||||
}else {
|
||||
page.addOrder(OrderItem.desc(defaultOrderField));
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
|
||||
package com.zcloud.common.utils;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 返回数据
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class R extends HashMap<String, Object> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public R() {
|
||||
put("code", 200);
|
||||
put("result", "success");
|
||||
}
|
||||
|
||||
public static R error() {
|
||||
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
|
||||
}
|
||||
|
||||
public static R error(String msg) {
|
||||
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
|
||||
}
|
||||
|
||||
public static R error(int code, String msg) {
|
||||
R r = new R();
|
||||
r.put("code", code);
|
||||
r.put("result", "failed");
|
||||
r.put("msg", msg);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static R ok(String msg) {
|
||||
R r = new R();
|
||||
r.put("msg", msg);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static R ok(Map<String, Object> map) {
|
||||
R r = new R();
|
||||
r.putAll(map);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static R ok() {
|
||||
return new R();
|
||||
}
|
||||
|
||||
public R put(String key, Object value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,404 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* RSA公钥/私钥/签名工具包
|
||||
* <p>
|
||||
* 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>
|
||||
* 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>
|
||||
* 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public class RSAUtils {
|
||||
|
||||
/** */
|
||||
/**
|
||||
* 加密算法RSA
|
||||
*/
|
||||
public static final String KEY_ALGORITHM = "RSA";
|
||||
|
||||
/** */
|
||||
/**
|
||||
* 签名算法
|
||||
*/
|
||||
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
|
||||
|
||||
/** */
|
||||
/**
|
||||
* 获取公钥的key
|
||||
*/
|
||||
private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUoHAavCikaZxjlDM6Km8cX+ye78F4oF39AcEfnE1p2Yn9pJ9WFxYZ4Vkh6F8SKMi7k4nYsKceqB1RwG996SvHQ5C3pM3nbXCP4K15ad6QhN4a7lzlbLhiJcyIKszvvK8ncUDw8mVQ0j/2mwxv05yH6LN9OKU6Hzm1ninpWeE+awIDAQAB\n";
|
||||
|
||||
/** */
|
||||
/**
|
||||
* 获取私钥的key
|
||||
*/
|
||||
private static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANSgcBq8KKRpnGOUMzoqbxxf7J7vwXigXf0BwR+cTWnZif2kn1YXFhnhWSHoXxIoyLuTidiwpx6oHVHAb33pK8dDkLekzedtcI/grXlp3pCE3hruXOVsuGIlzIgqzO+8rydxQPDyZVDSP/abDG/TnIfos304pTofObWeKelZ4T5rAgMBAAECgYEAt2Dvjn885h+Xm2JTlBTI40Xvw1uwFqLorK54qxSYx3OwySrTqOIcU5HA17ebVwQJq40hU9t3Jr+DGeDHx2X0NEJ0LXuDMzeWxUwUMbdxxM7OXS6Zuhy73C99DyAweLP9K1H2J/y1+eJ4Zx/0mTiAgCKJFNWAQBZwGl5Zu2zoHOECQQDw0UlrOUfloxK3hfVSWlfL7+onP+z/qa9bzemSg676sAJqA8d5ao8V532OBOtZxfPSlh4igC0lpY2vnCRHrwJZAkEA4ggpMS4o+rfFmNslNzI0m3VFDiLYmghYIqTLHtLYqAbY8QVfFd8bl920t5LQAlTsI3q9Spsu8y7AnAWmYydGYwJAN+tBMya/7TDqvbbbel4EGRUCuE59x/gtAhJUdHMjhI6uYNOz1BvMUffJDdtSkywGLBYztSsyUJWayvZk7khTMQJAALM7xW46LESjdQzAucILDaw4UYnkF94Mv9a41lia2TJkO6Ljn4K4aCkEpUjsIgW3UYjQy0ldxN0RNaqC0G3PtwJAFafiLzcls6qzyAlh5PqM5cJrs+Xa0rHR322/AlSyuxW6wRzUX/zSoorP34JCjRPT5DzUeHMVvr6S2BE8k/8XYg==";
|
||||
|
||||
/** */
|
||||
/**
|
||||
* RSA最大加密明文大小
|
||||
*/
|
||||
private static final int MAX_ENCRYPT_BLOCK = 117;
|
||||
|
||||
/** */
|
||||
/**
|
||||
* RSA最大解密密文大小
|
||||
*/
|
||||
private static final int MAX_DECRYPT_BLOCK = 128;
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 生成密钥对(公钥和私钥)
|
||||
* </p>
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Map<String, Object> genKeyPair() throws Exception {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
|
||||
keyPairGen.initialize(1024);
|
||||
KeyPair keyPair = keyPairGen.generateKeyPair();
|
||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
|
||||
Map<String, Object> keyMap = new HashMap<String, Object>(2);
|
||||
keyMap.put(PUBLIC_KEY, publicKey);
|
||||
keyMap.put(PRIVATE_KEY, privateKey);
|
||||
return keyMap;
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 用私钥对信息生成数字签名
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* 已加密数据
|
||||
* @param privateKey
|
||||
* 私钥(BASE64编码)
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String sign(byte[] data, String privateKey) throws Exception {
|
||||
byte[] keyBytes = Base64Utils.decode(privateKey);
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
||||
signature.initSign(privateK);
|
||||
signature.update(data);
|
||||
return Base64Utils.encode(signature.sign());
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 校验数字签名
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* 已加密数据
|
||||
* @param publicKey
|
||||
* 公钥(BASE64编码)
|
||||
* @param sign
|
||||
* 数字签名
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*
|
||||
*/
|
||||
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
|
||||
byte[] keyBytes = Base64Utils.decode(publicKey);
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
PublicKey publicK = keyFactory.generatePublic(keySpec);
|
||||
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
||||
signature.initVerify(publicK);
|
||||
signature.update(data);
|
||||
return signature.verify(Base64Utils.decode(sign));
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <P>
|
||||
* 私钥解密
|
||||
* </p>
|
||||
*
|
||||
* @param encryptedData
|
||||
* 已加密数据
|
||||
* @param privateKey
|
||||
* 私钥(BASE64编码)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
|
||||
byte[] keyBytes = Base64Utils.decode(privateKey);
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateK);
|
||||
int inputLen = encryptedData.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段解密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_DECRYPT_BLOCK;
|
||||
}
|
||||
byte[] decryptedData = out.toByteArray();
|
||||
out.close();
|
||||
return decryptedData;
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 公钥解密
|
||||
* </p>
|
||||
*
|
||||
* @param encryptedData
|
||||
* 已加密数据
|
||||
* @param publicKey
|
||||
* 公钥(BASE64编码)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
|
||||
byte[] keyBytes = Base64Utils.decode(publicKey);
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
Key publicK = keyFactory.generatePublic(x509KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(Cipher.DECRYPT_MODE, publicK);
|
||||
int inputLen = encryptedData.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段解密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_DECRYPT_BLOCK;
|
||||
}
|
||||
byte[] decryptedData = out.toByteArray();
|
||||
out.close();
|
||||
return decryptedData;
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 公钥加密
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* 源数据
|
||||
* @param publicKey
|
||||
* 公钥(BASE64编码)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
|
||||
byte[] keyBytes = Base64Utils.decode(publicKey);
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
Key publicK = keyFactory.generatePublic(x509KeySpec);
|
||||
// 对数据加密
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicK);
|
||||
int inputLen = data.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段加密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher.doFinal(data, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_ENCRYPT_BLOCK;
|
||||
}
|
||||
byte[] encryptedData = out.toByteArray();
|
||||
out.close();
|
||||
return encryptedData;
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 私钥加密
|
||||
* </p>
|
||||
*
|
||||
* @param data
|
||||
* 源数据
|
||||
* @param privateKey
|
||||
* 私钥(BASE64编码)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
|
||||
byte[] keyBytes = Base64Utils.decode(privateKey);
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(Cipher.ENCRYPT_MODE, privateK);
|
||||
int inputLen = data.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段加密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher.doFinal(data, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_ENCRYPT_BLOCK;
|
||||
}
|
||||
byte[] encryptedData = out.toByteArray();
|
||||
out.close();
|
||||
return encryptedData;
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 获取私钥
|
||||
* </p>
|
||||
*
|
||||
* @param keyMap
|
||||
* 密钥对
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
|
||||
Key key = (Key) keyMap.get(PRIVATE_KEY);
|
||||
return Base64Utils.encode(key.getEncoded());
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 获取私钥
|
||||
* </p>
|
||||
*
|
||||
* @param keyMap
|
||||
* 密钥对
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String getPrivateKey() {
|
||||
return PRIVATE_KEY;
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 获取公钥
|
||||
* </p>
|
||||
*
|
||||
* @param keyMap
|
||||
* 密钥对
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
|
||||
Key key = (Key) keyMap.get(PUBLIC_KEY);
|
||||
return Base64Utils.encode(key.getEncoded());
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* <p>
|
||||
* 获取公钥
|
||||
* </p>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String getPublicKey() throws Exception {
|
||||
return PUBLIC_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* java端公钥加密
|
||||
*/
|
||||
public static String encryptedDataOnJava(String data, String PUBLICKEY) {
|
||||
try {
|
||||
data = Base64Utils.encode(encryptByPublicKey(data.getBytes(), PUBLICKEY));
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* java端私钥解密
|
||||
*/
|
||||
public static String decryptDataOnJava(String data, String PRIVATEKEY) {
|
||||
String temp = "";
|
||||
try {
|
||||
byte[] rs = Base64Utils.decode(data);
|
||||
temp = new String(RSAUtils.decryptByPrivateKey(rs, PRIVATEKEY),"UTF-8"); //以utf-8的方式生成字符串
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Map<String, Object> keyMap = null;
|
||||
try {
|
||||
keyMap = RSAUtils.genKeyPair();
|
||||
String publicKey = RSAUtils.getPublicKey(keyMap);
|
||||
String privateKey = RSAUtils.getPrivateKey(keyMap);
|
||||
System.err.println("公钥: \n\r" + publicKey);
|
||||
System.err.println("私钥: \n\r" + privateKey);
|
||||
// 公钥:
|
||||
// MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDE8aNkz3X5f96bW2EJ3fRQsEmtgrIzLSCSJZLf1WBay0ihEideK45md5UZIFB6HSWwBaKD4z1uAMdt5esn0AIvrQS8+nlnB+Fohzxg7yY2ooDLP2az0WVKzepbeg8igq+jflUh7/+rvndiJAnv+mnMbibFqhYsDAJ3Zq82FkOeXQIDAQAB
|
||||
// 私钥:
|
||||
// MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMTxo2TPdfl/3ptbYQnd9FCwSa2CsjMtIJIlkt/VYFrLSKESJ14rjmZ3lRkgUHodJbAFooPjPW4Ax23l6yfQAi+tBLz6eWcH4WiHPGDvJjaigMs/ZrPRZUrN6lt6DyKCr6N+VSHv/6u+d2IkCe/6acxuJsWqFiwMAndmrzYWQ55dAgMBAAECgYB1gfPKz5oFjw0ERyaEG6GNj1G2rFek/1UCvlZ/JTJDmi0wpcNFhdmGO+2DO2upIMD+4K3R4YEipGZZpSiE7bCPM1uIerVAi0efTQMZKSrreud29Z/6xN0166GthAj30AjrwxfNAhoUNQXcG2NQJmfUpPlV95Cjh2b6tTlLdU9foQJBAO2zrzYeLiBrhEOZqr5JC8zUdseGSKCwIvZDwQ+s8GuuSVpm1q9mHOL3TODNlawfst78o9QBkk2MyKP7Voe6C6UCQQDUGr/A7XTvV39fqO4V+BcSLDCpxTHJ8UUWiRovXhDMn0TjqeRnDiRC9YuMf5XCXwDkYnK/u3O2maZugrcgUqpZAkBgd4zC9MqZg6jg2mtN4E02qn8uCFRPSkxWDzc5ymCkAs5oLtYvxswwXFbJ4QU+Hns0Pemq75xVdq4yxpzeZmW1AkEAvOi+FJTpaypg9dA9jS+TTMoy5WIOgC/1OqcNvVZoW/cWojZ0iRzdSw3rJk2UErQO1VqhnQbVfrLGuvKNK6q0sQJATbmrgK1KDaAS3Ns8MI6pDKWWHaAy8Vrnwz4nRIX2C0FKLTYwbNPrvVHdpD0ItZ8p9wiAL6HVn5ipxbz6v0l1uA==
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
|
||||
package com.zcloud.common.utils;
|
||||
|
||||
/**
|
||||
* Redis所有Keys
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class RedisKeys {
|
||||
|
||||
public static String getSysConfigKey(String key){
|
||||
return "sys:config:" + key;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Redis工具类
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class RedisUtils {
|
||||
@Autowired
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
@Autowired
|
||||
private ValueOperations<String, String> valueOperations;
|
||||
@Autowired
|
||||
private HashOperations<String, String, Object> hashOperations;
|
||||
@Autowired
|
||||
private ListOperations<String, Object> listOperations;
|
||||
@Autowired
|
||||
private SetOperations<String, Object> setOperations;
|
||||
@Autowired
|
||||
private ZSetOperations<String, Object> zSetOperations;
|
||||
/** 默认过期时长,单位:秒 */
|
||||
public final static long DEFAULT_EXPIRE = 60 * 60 * 24;
|
||||
/** 不设置过期时长 */
|
||||
public final static long NOT_EXPIRE = -1;
|
||||
private final static Gson gson = new Gson();
|
||||
|
||||
public void set(String key, Object value, long expire){
|
||||
valueOperations.set(key, toJson(value));
|
||||
if(expire != NOT_EXPIRE){
|
||||
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
public void set(String key, Object value, long expire, TimeUnit unit){
|
||||
valueOperations.set(key, toJson(value));
|
||||
if(expire != NOT_EXPIRE){
|
||||
redisTemplate.expire(key, expire, unit);
|
||||
}
|
||||
}
|
||||
public void set(String key, Object value){
|
||||
set(key, value, DEFAULT_EXPIRE);
|
||||
}
|
||||
|
||||
public <T> T get(String key, Class<T> clazz, long expire) {
|
||||
String value = valueOperations.get(key);
|
||||
if(expire != NOT_EXPIRE){
|
||||
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
|
||||
}
|
||||
return value == null ? null : fromJson(value, clazz);
|
||||
}
|
||||
|
||||
public <T> T get(String key, Class<T> clazz) {
|
||||
return get(key, clazz, NOT_EXPIRE);
|
||||
}
|
||||
|
||||
public String get(String key, long expire) {
|
||||
String value = valueOperations.get(key);
|
||||
if(expire != NOT_EXPIRE){
|
||||
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public String get(String key, long expire, TimeUnit unit) {
|
||||
String value = valueOperations.get(key);
|
||||
if(expire != NOT_EXPIRE){
|
||||
redisTemplate.expire(key, expire, unit);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
return get(key, NOT_EXPIRE);
|
||||
}
|
||||
|
||||
public void delete(String key) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object转成JSON数据
|
||||
*/
|
||||
private String toJson(Object object){
|
||||
if(object instanceof Integer || object instanceof Long || object instanceof Float ||
|
||||
object instanceof Double || object instanceof Boolean || object instanceof String){
|
||||
return String.valueOf(object);
|
||||
}
|
||||
return gson.toJson(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON数据,转成Object
|
||||
*/
|
||||
private <T> T fromJson(String json, Class<T> clazz){
|
||||
return gson.fromJson(json, clazz);
|
||||
}
|
||||
public Map<String, Object> getSpecifiedFields(String hashKey, List<String> fields) {
|
||||
HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
|
||||
List<String> values = hashOps.multiGet(hashKey, fields);
|
||||
|
||||
Map<String, Object> fieldValuesMap = new HashMap<>();
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
String field = fields.get(i);
|
||||
Object value = values.get(i);
|
||||
// Assuming you want to skip null values
|
||||
if (value != null) {
|
||||
fieldValuesMap.put(field, value);
|
||||
}
|
||||
}
|
||||
return fieldValuesMap;
|
||||
}
|
||||
/**
|
||||
* 查询所有key
|
||||
* @return
|
||||
*/
|
||||
public Set<String> getKeys() {
|
||||
return redisTemplate.keys("*");
|
||||
}
|
||||
/**
|
||||
* 查询所有key
|
||||
* @return
|
||||
*/
|
||||
public Set<String> getKeys(String keys) {
|
||||
return redisTemplate.keys(keys);
|
||||
}
|
||||
|
||||
|
||||
public void setSet(long expire, String key, String... value){
|
||||
setOperations.add(key, value);
|
||||
if(expire != NOT_EXPIRE){
|
||||
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSet(long expire, TimeUnit unit, String key, String... value){
|
||||
setOperations.add(key, value);
|
||||
if(expire != NOT_EXPIRE){
|
||||
redisTemplate.expire(key, expire, unit);
|
||||
}
|
||||
}
|
||||
public void setSet(String key, String... value){
|
||||
setSet(DEFAULT_EXPIRE, key, value);
|
||||
}
|
||||
|
||||
public Set<Object> union(Collection<String> keys){
|
||||
return setOperations.union(keys);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class RequestMap {
|
||||
|
||||
/**
|
||||
* 从request中获得参数Map,并返回可读的Map
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public static Map getParameterMap(HttpServletRequest request) {
|
||||
// 参数Map
|
||||
Map properties = request.getParameterMap();
|
||||
// 返回值Map
|
||||
Map returnMap = new HashMap();
|
||||
Iterator entries = properties.entrySet().iterator();
|
||||
Map.Entry entry;
|
||||
String name = "";
|
||||
String value = "";
|
||||
while (entries.hasNext()) {
|
||||
entry = (Map.Entry) entries.next();
|
||||
name = (String) entry.getKey();
|
||||
Object valueObj = entry.getValue();
|
||||
if(null == valueObj){
|
||||
value = "";
|
||||
}else if(valueObj instanceof String[]){
|
||||
String[] values = (String[])valueObj;
|
||||
for(int i=0;i<values.length;i++){
|
||||
value = values[i] + ",";
|
||||
}
|
||||
value = value.substring(0, value.length()-1);
|
||||
}else{
|
||||
value = valueObj.toString();
|
||||
}
|
||||
returnMap.put(name, value);
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class SerializationUtils {
|
||||
/**
|
||||
* 序列化工具类
|
||||
*/
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* 将对象序列化为JSON字符串
|
||||
*
|
||||
* @param obj 要序列化的对象
|
||||
* @return 序列化后的JSON字符串
|
||||
* @throws JsonProcessingException JSON处理异常
|
||||
*/
|
||||
public static String serialize(Object obj) throws JsonProcessingException {
|
||||
return objectMapper.writeValueAsString(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将JSON字符串反序列化为指定类型的对象
|
||||
*
|
||||
* @param json 要反序列化的JSON字符串
|
||||
* @param clazz 对象的类型
|
||||
* @return 反序列化后的对象
|
||||
* @throws JsonProcessingException JSON处理异常
|
||||
*/
|
||||
public static <T> T deserialize(String json, Class<T> clazz) throws JsonProcessingException {
|
||||
return objectMapper.readValue(json, clazz);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.zcloud.common.exception.ZException;
|
||||
import com.zcloud.modules.sys.entity.SysUserEntity;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.session.Session;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* Shiro工具类
|
||||
*/
|
||||
public class ShiroUtils {
|
||||
|
||||
public static Session getSession() {
|
||||
return SecurityUtils.getSubject().getSession();
|
||||
}
|
||||
|
||||
public static Subject getSubject() {
|
||||
return SecurityUtils.getSubject();
|
||||
}
|
||||
|
||||
public static SysUserEntity getUserEntity() {
|
||||
return (SysUserEntity)SecurityUtils.getSubject().getPrincipal();
|
||||
}
|
||||
|
||||
public static String getUserId() {
|
||||
return getUserEntity().getUserId();
|
||||
}
|
||||
|
||||
public static void setSessionAttribute(Object key, Object value) {
|
||||
getSession().setAttribute(key, value);
|
||||
}
|
||||
|
||||
public static Object getSessionAttribute(Object key) {
|
||||
return getSession().getAttribute(key);
|
||||
}
|
||||
|
||||
public static boolean isLogin() {
|
||||
return SecurityUtils.getSubject().getPrincipal() != null;
|
||||
}
|
||||
|
||||
public static String getKaptcha(String key) {
|
||||
Object kaptcha = getSessionAttribute(key);
|
||||
if(kaptcha == null){
|
||||
throw new ZException("验证码已失效");
|
||||
}
|
||||
getSession().removeAttribute(key);
|
||||
return kaptcha.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class SnowflakeIdFactory {
|
||||
|
||||
private final long twepoch = 1288834974657L;
|
||||
private final long workerIdBits = 5L;
|
||||
private final long datacenterIdBits = 5L;
|
||||
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
|
||||
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
|
||||
private final long sequenceBits = 12L;
|
||||
private final long workerIdShift = sequenceBits;
|
||||
private final long datacenterIdShift = sequenceBits + workerIdBits;
|
||||
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
||||
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
|
||||
|
||||
private long workerId;
|
||||
private long datacenterId;
|
||||
private long sequence = 0L;
|
||||
private long lastTimestamp = -1L;
|
||||
|
||||
|
||||
|
||||
public SnowflakeIdFactory(long workerId, long datacenterId) {
|
||||
if (workerId > maxWorkerId || workerId < 0) {
|
||||
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
|
||||
}
|
||||
if (datacenterId > maxDatacenterId || datacenterId < 0) {
|
||||
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
this.datacenterId = datacenterId;
|
||||
}
|
||||
|
||||
public synchronized long nextId() {
|
||||
long timestamp = timeGen();
|
||||
if (timestamp < lastTimestamp) {
|
||||
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
|
||||
}
|
||||
if (lastTimestamp == timestamp) {
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence == 0) {
|
||||
timestamp = tilNextMillis(lastTimestamp);
|
||||
}
|
||||
} else {
|
||||
sequence = 0L;
|
||||
}
|
||||
|
||||
lastTimestamp = timestamp;
|
||||
return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
|
||||
}
|
||||
|
||||
protected long tilNextMillis(long lastTimestamp) {
|
||||
long timestamp = timeGen();
|
||||
while (timestamp <= lastTimestamp) {
|
||||
timestamp = timeGen();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
protected long timeGen() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public static void testProductIdByMoreThread(int dataCenterId, int workerId, int n) throws InterruptedException {
|
||||
List<Thread> tlist = new ArrayList<>();
|
||||
Set<Long> setAll = new HashSet<>();
|
||||
CountDownLatch cdLatch = new CountDownLatch(10);
|
||||
long start = System.currentTimeMillis();
|
||||
int threadNo = dataCenterId;
|
||||
Map<String,SnowflakeIdFactory> idFactories = new HashMap<>();
|
||||
for(int i=0;i<10;i++){
|
||||
//用线程名称做map key.
|
||||
idFactories.put("snowflake"+i,new SnowflakeIdFactory(workerId, threadNo++));
|
||||
}
|
||||
for(int i=0;i<10;i++){
|
||||
Thread temp =new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Set<Long> setId = new HashSet<>();
|
||||
SnowflakeIdFactory idWorker = idFactories.get(Thread.currentThread().getName());
|
||||
for(int j=0;j<n;j++){
|
||||
setId.add(idWorker.nextId());
|
||||
}
|
||||
synchronized (setAll){
|
||||
setAll.addAll(setId);
|
||||
}
|
||||
cdLatch.countDown();
|
||||
}
|
||||
},"snowflake"+i);
|
||||
tlist.add(temp);
|
||||
}
|
||||
for(int j=0;j<10;j++){
|
||||
tlist.get(j).start();
|
||||
}
|
||||
cdLatch.await();
|
||||
|
||||
long end1 = System.currentTimeMillis() - start;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void testProductId(int dataCenterId, int workerId, int n){
|
||||
SnowflakeIdFactory idWorker = new SnowflakeIdFactory(workerId, dataCenterId);
|
||||
SnowflakeIdFactory idWorker2 = new SnowflakeIdFactory(workerId+1, dataCenterId);
|
||||
Set<Long> setOne = new HashSet<>();
|
||||
Set<Long> setTow = new HashSet<>();
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < n; i++) {
|
||||
setOne.add(idWorker.nextId());//加入set
|
||||
}
|
||||
long end1 = System.currentTimeMillis() - start;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
setTow.add(idWorker2.nextId());//加入set
|
||||
}
|
||||
long end2 = System.currentTimeMillis() - start;
|
||||
|
||||
setOne.addAll(setTow);
|
||||
|
||||
}
|
||||
|
||||
public static void testPerSecondProductIdNums(){
|
||||
SnowflakeIdFactory idWorker = new SnowflakeIdFactory(1, 2);
|
||||
long start = System.currentTimeMillis();
|
||||
int count = 0;
|
||||
for (int i = 0; System.currentTimeMillis()-start<1000; i++,count=i) {
|
||||
idWorker.nextId();
|
||||
//log.error("{}",idWorker.nextId());
|
||||
}
|
||||
long end = System.currentTimeMillis()-start;
|
||||
System.out.println(end);
|
||||
System.out.println(count);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SnowflakeIdFactory idWorker = new SnowflakeIdFactory(1, 2);
|
||||
System.out.println(idWorker.nextId());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
|
||||
package com.zcloud.common.utils;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Spring Context 工具类
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class SpringContextUtils implements ApplicationContextAware {
|
||||
public static ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
SpringContextUtils.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public static Object getBean(String name) {
|
||||
return applicationContext.getBean(name);
|
||||
}
|
||||
|
||||
public static <T> T getBean(String name, Class<T> requiredType) {
|
||||
return applicationContext.getBean(name, requiredType);
|
||||
}
|
||||
|
||||
public static boolean containsBean(String name) {
|
||||
return applicationContext.containsBean(name);
|
||||
}
|
||||
|
||||
public static boolean isSingleton(String name) {
|
||||
return applicationContext.isSingleton(name);
|
||||
}
|
||||
|
||||
public static Class<? extends Object> getType(String name) {
|
||||
return applicationContext.getType(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,419 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* 说明:常用工具
|
||||
* 作者:luoxiaobao
|
||||
* 官网:www.qdkjchina.com
|
||||
*/
|
||||
public class Tools {
|
||||
|
||||
/**
|
||||
* 随机生成六位数验证码
|
||||
* @return
|
||||
*/
|
||||
public static int getRandomNum(){
|
||||
Random r = new Random();
|
||||
return r.nextInt(900000)+100000;//(Math.random()*(999999-100000)+100000)
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机生成四位数验证码
|
||||
* @return
|
||||
*/
|
||||
public static int getRandomNum4(){
|
||||
Random r = new Random();
|
||||
return r.nextInt(9000)+1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测字符串是否不为空(null,"","null")
|
||||
* @param s
|
||||
* @return 不为空则返回true,否则返回false
|
||||
*/
|
||||
public static boolean notEmpty(String s){
|
||||
return s!=null && !"".equals(s) && !"null".equals(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测字符串是否为空(null,"","null")
|
||||
* @param s
|
||||
* @return 为空则返回true,不否则返回false
|
||||
*/
|
||||
public static boolean isEmpty(String s){
|
||||
return s==null || "".equals(s) || "null".equals(s);
|
||||
}
|
||||
public static boolean isEmpty (Object obj) {
|
||||
return obj ==null || "".equals(obj);
|
||||
}
|
||||
/**
|
||||
* 字符串转换为字符串数组
|
||||
* @param str 字符串
|
||||
* @param splitRegex 分隔符
|
||||
* @return
|
||||
*/
|
||||
public static String[] str2StrArray(String str,String splitRegex){
|
||||
if(isEmpty(str)){
|
||||
return null;
|
||||
}
|
||||
return str.split(splitRegex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用默认的分隔符(,)将字符串转换为字符串数组
|
||||
* @param str 字符串
|
||||
* @return
|
||||
*/
|
||||
public static String[] str2StrArray(String str){
|
||||
return str2StrArray(str,",\\s*");
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个数组,拿到不同的元素
|
||||
* @param str 字符串
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> compare(T[] t1, T[] t2) {
|
||||
List<T> list1 = Arrays.asList(t1);
|
||||
List<T> list2 = Arrays.asList(t2);
|
||||
//用来保存最后结果的集合
|
||||
List<T> list3 = new ArrayList<>();
|
||||
for (T t : t2) {
|
||||
if (!list1.contains(t)) {
|
||||
list3.add(t);
|
||||
}
|
||||
}
|
||||
for (T t:t1) {
|
||||
if (!list2.contains(t)) {
|
||||
list3.add(t);
|
||||
}
|
||||
}
|
||||
return list3;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证邮箱
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
public static boolean checkEmail(String email){
|
||||
boolean flag = false;
|
||||
try{
|
||||
String check = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
|
||||
Pattern regex = Pattern.compile(check);
|
||||
Matcher matcher = regex.matcher(email);
|
||||
flag = matcher.matches();
|
||||
}catch(Exception e){
|
||||
flag = false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证手机号码
|
||||
* @param mobileNumber
|
||||
* @return
|
||||
*/
|
||||
public static boolean checkMobileNumber(String mobileNumber){
|
||||
boolean flag = false;
|
||||
try{
|
||||
Pattern regex = Pattern.compile("^(((13[0-9])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8})|(0\\d{2}-\\d{8})|(0\\d{3}-\\d{7})$");
|
||||
Matcher matcher = regex.matcher(mobileNumber);
|
||||
flag = matcher.matches();
|
||||
}catch(Exception e){
|
||||
flag = false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测KEY是否正确
|
||||
* @param paraname 传入参数
|
||||
* @param FKEY 接收的 KEY
|
||||
* @return 为空则返回true,不否则返回false
|
||||
*/
|
||||
public static boolean checkKey(String paraname, String FKEY){
|
||||
paraname = (null == paraname)? "":paraname;
|
||||
return MD5.md5(paraname+DateUtil.getDays()+",fh,").equals(FKEY);
|
||||
}
|
||||
/**
|
||||
转半角的函数(DBC case)<br/><br/>
|
||||
全角空格为12288,半角空格为32
|
||||
其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
|
||||
* @param input 任意字符串
|
||||
* @return 半角字符串
|
||||
*
|
||||
*/
|
||||
public static String ToDBC(String input) {
|
||||
char[] c = input.toCharArray();
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
if (c[i] == 12288) {
|
||||
//全角空格为12288,半角空格为32
|
||||
c[i] = (char) 32;
|
||||
continue;
|
||||
}
|
||||
if (c[i] > 65280 && c[i] < 65375)
|
||||
//其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
|
||||
c[i] = (char) (c[i] - 65248);
|
||||
}
|
||||
return new String(c);
|
||||
}
|
||||
|
||||
public static String replaceBlank(String str) {
|
||||
String dest = "";
|
||||
if (str != null) {
|
||||
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
|
||||
Matcher m = p.matcher(str);
|
||||
dest = m.replaceAll("");
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
public static String excelHandle (String string) {
|
||||
String aString = string.replaceAll(" ", "");
|
||||
aString = ToDBC(aString);
|
||||
aString = replaceBlank(aString);
|
||||
return aString;
|
||||
}
|
||||
public static String excelHandle (Object object) {
|
||||
String aString = object.toString().replaceAll(" ", "");
|
||||
aString = ToDBC(aString);
|
||||
aString = replaceBlank(aString);
|
||||
return aString;
|
||||
}
|
||||
public static String get32UUID() {
|
||||
String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public static String uploadFile(MultipartFile file, String folder) {
|
||||
String ffile = DateUtil.getDays();
|
||||
String fileName = get32UUID() + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
|
||||
String path = "/uploadFiles/" + folder + "/" + ffile;
|
||||
FileUploadUtil.sshSftp(file, fileName, path);
|
||||
return "/uploadFiles/" + folder + "/" + ffile +"/" + fileName;
|
||||
}
|
||||
|
||||
public static boolean isNotBlank(Object obj){
|
||||
return obj!=null &&!"".equals(obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 构建树形结构
|
||||
*
|
||||
* @param entities 实体集合
|
||||
* idFieldName id字段名称
|
||||
* parentIdFieldName parentId字段名称
|
||||
* childrenFieldName children字段名称
|
||||
**/
|
||||
public static <T> List<T> buildEntityTree(List<T> entities, String idFieldName, String parentIdFieldName, String childrenFieldName) {
|
||||
if (entities == null || entities.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<T> result = new ArrayList<>();
|
||||
|
||||
try {
|
||||
Field idField = getField(entities.get(0).getClass(), idFieldName);
|
||||
Field parentIdField = getField(entities.get(0).getClass(), parentIdFieldName);
|
||||
Field childrenField = getField(entities.get(0).getClass(), childrenFieldName);
|
||||
|
||||
if (idField == null || parentIdField == null) {
|
||||
throw new IllegalArgumentException("Invalid idFieldName or parentIdFieldName or childrenField");
|
||||
}
|
||||
|
||||
Map<Object, T> entityMap = new HashMap<>();
|
||||
for (T entity : entities) {
|
||||
idField.setAccessible(true);
|
||||
Object id = idField.get(entity);
|
||||
entityMap.put(id, entity);
|
||||
}
|
||||
|
||||
for (T entity : entities) {
|
||||
parentIdField.setAccessible(true);
|
||||
Object parentId = parentIdField.get(entity);
|
||||
if(parentId == null || parentId.equals("0") || parentId.equals("-1")){
|
||||
result.add(entity); // 根节点
|
||||
|
||||
}else{
|
||||
T parentEntity = entityMap.get(parentId);
|
||||
if (parentEntity != null) {
|
||||
if (childrenField != null) {
|
||||
childrenField.setAccessible(true);
|
||||
List<T> children = (List<T>) childrenField.get(parentEntity);
|
||||
if (children == null) {
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
children.add(entity);
|
||||
childrenField.set(parentEntity, children);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 构建树形结构
|
||||
*
|
||||
* @param entities 实体集合
|
||||
* idFieldName id字段名称
|
||||
* parentIdFieldName parentId字段名称
|
||||
* childrenFieldName children字段名称
|
||||
* rootId 根节点id
|
||||
**/
|
||||
public static <T> List<T> buildEntityTree(List<T> entities, String idFieldName, String parentIdFieldName, String childrenFieldName, String rootId) {
|
||||
if (entities == null || entities.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<T> result = new ArrayList<>();
|
||||
|
||||
try {
|
||||
Field idField = getField(entities.get(0).getClass(), idFieldName);
|
||||
Field parentIdField = getField(entities.get(0).getClass(), parentIdFieldName);
|
||||
Field childrenField = getField(entities.get(0).getClass(), childrenFieldName);
|
||||
|
||||
if (idField == null || parentIdField == null) {
|
||||
throw new IllegalArgumentException("Invalid idFieldName or parentIdFieldName or childrenField");
|
||||
}
|
||||
|
||||
Map<Object, T> entityMap = new HashMap<>();
|
||||
for (T entity : entities) {
|
||||
idField.setAccessible(true);
|
||||
Object id = idField.get(entity);
|
||||
entityMap.put(id, entity);
|
||||
}
|
||||
|
||||
for (T entity : entities) {
|
||||
parentIdField.setAccessible(true);
|
||||
Object parentId = parentIdField.get(entity);
|
||||
if(parentId == null || parentId.equals("0") || parentId.equals("-1")
|
||||
|| (!ObjectUtils.isEmpty(rootId) && parentId.equals(rootId))){
|
||||
result.add(entity); // 根节点
|
||||
|
||||
}else{
|
||||
T parentEntity = entityMap.get(parentId);
|
||||
if (parentEntity != null) {
|
||||
if (childrenField != null) {
|
||||
childrenField.setAccessible(true);
|
||||
List<T> children = (List<T>) childrenField.get(parentEntity);
|
||||
if (children == null) {
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
children.add(entity);
|
||||
childrenField.set(parentEntity, children);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static Field getField(Class<?> clazz, String fieldName) {
|
||||
try {
|
||||
return clazz.getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// 若当前类不存在指定字段,则尝试从父类中获取
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
if (superClass != null && superClass != Object.class) {
|
||||
return getField(superClass, fieldName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的后缀名
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 文件后缀名,如果没有后缀名则返回空字符串
|
||||
*/
|
||||
public static String getFileExtension(String fileName) {
|
||||
if (fileName == null || fileName.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
int lastDotIndex = fileName.lastIndexOf('.');
|
||||
if (lastDotIndex == -1) {
|
||||
return ""; // 没有后缀名
|
||||
}
|
||||
|
||||
return fileName.substring(lastDotIndex + 1).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个版本号的大小
|
||||
*
|
||||
* @param version1 第一个版本号字符串,各部分由点(.)分隔
|
||||
* @param version2 第二个版本号字符串,各部分由点(.)分隔
|
||||
* @return 返回值为1表示version1大于version2,-1表示version1小于version2,0表示两者相等
|
||||
*/
|
||||
public static int compareVersion(String version1, String version2) {
|
||||
// 将版本号字符串按照点(.)分割成各个部分
|
||||
String[] versionParts1 = version1.split("\\.");
|
||||
String[] versionParts2 = version2.split("\\.");
|
||||
// 确定比较的长度,取两个版本号部分数的最大值
|
||||
int length = Math.max(versionParts1.length, versionParts2.length);
|
||||
// 遍历每个部分进行比较
|
||||
for (int i = 0; i < length; i++) {
|
||||
// 获取当前部分的版本号,如果超出数组长度则默认为0
|
||||
int part1 = i < versionParts1.length ? Integer.parseInt(versionParts1[i]) : 0;
|
||||
int part2 = i < versionParts2.length ? Integer.parseInt(versionParts2[i]) : 0;
|
||||
// 比较两个版本号的部分,如果不同则返回比较结果
|
||||
if (part1 < part2) {
|
||||
return -1;
|
||||
} else if (part1 > part2) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// 如果所有部分都相等,则返回0
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static String videoTimeMinFormat(Double videoTime) {
|
||||
int minutes = (int) (videoTime / 60);
|
||||
int remainingSeconds = (int) (videoTime % 60);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (minutes < 10) {
|
||||
sb.append("0").append(minutes);
|
||||
} else {
|
||||
sb.append(minutes);
|
||||
}
|
||||
sb.append(":");
|
||||
if (remainingSeconds < 10) {
|
||||
sb.append("0").append(remainingSeconds);
|
||||
} else {
|
||||
sb.append(remainingSeconds);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
String aString = " afjaisjfasjfasij ";
|
||||
String bString = "";
|
||||
bString= excelHandle(aString);
|
||||
System.out.println("bString:"+bString+".");
|
||||
System.out.println("aString:"+aString+".");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import com.zcloud.modules.sys.service.ShiroService;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
|
||||
public class UserUtils {
|
||||
public static String getUserIdFromRequest(HttpServletRequest request, ShiroService shiroService) {
|
||||
// 从HTTP请求头中获取token
|
||||
String token = request.getHeader("token");
|
||||
// 使用token获取用户信息,并返回用户ID
|
||||
return shiroService.queryByToken(token).getUserId();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package com.zcloud.common.utils;
|
||||
|
||||
import org.jdom2.Document;
|
||||
import org.jdom2.Element;
|
||||
import org.jdom2.JDOMException;
|
||||
import org.jdom2.input.SAXBuilder;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class XMLUtil {
|
||||
/**
|
||||
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
|
||||
* @param strxml
|
||||
* @return
|
||||
* @throws JDOMException
|
||||
* @throws IOException
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付成功,返回微信那服务器
|
||||
* @param return_code
|
||||
* @param return_msg
|
||||
* @return
|
||||
*/
|
||||
public static String setXML(String return_code, String return_msg) {
|
||||
return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
|
||||
}
|
||||
|
||||
public static String createXML(Map<String,Object> map){
|
||||
Set<Entry<String,Object>> set=map.entrySet();
|
||||
set.iterator();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
|
||||
package com.zcloud.common.validator;
|
||||
|
||||
import com.zcloud.common.exception.ZException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
/**
|
||||
* 数据校验
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class Assert {
|
||||
|
||||
public static void isBlank(String str, String message) {
|
||||
if (StringUtils.isBlank(str)) {
|
||||
throw new ZException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void isNull(Object object, String message) {
|
||||
if (object == null) {
|
||||
throw new ZException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.zcloud.common.validator;
|
||||
|
||||
import com.zcloud.common.exception.ZException;
|
||||
import com.zcloud.common.utils.Constant;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* hibernate-validator校验工具类
|
||||
*
|
||||
* 参考文档:http://docs.jboss.org/hibernate/validator/5.4/reference/en-US/html_single/
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ValidatorUtils {
|
||||
private static Validator validator;
|
||||
|
||||
static {
|
||||
validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验对象
|
||||
* @param object 待校验对象
|
||||
* @param groups 待校验的组
|
||||
* @throws ZException 校验不通过,则报RRException异常
|
||||
*/
|
||||
public static void validateEntity(Object object, Class<?>... groups)
|
||||
throws ZException {
|
||||
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
|
||||
if (!constraintViolations.isEmpty()) {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
for (ConstraintViolation<Object> constraint : constraintViolations) {
|
||||
msg.append(constraint.getMessage()).append("<br>");
|
||||
}
|
||||
throw new ZException(msg.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateEntity(Object object, Constant.CloudService type) {
|
||||
validateEntity(object, type.getValidatorGroupClass());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
|
||||
package com.zcloud.common.validator.group;
|
||||
|
||||
/**
|
||||
* 新增数据 Group
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface AddGroup {
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
|
||||
package com.zcloud.common.validator.group;
|
||||
|
||||
/**
|
||||
* 阿里云
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface AliyunGroup {
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
|
||||
package com.zcloud.common.validator.group;
|
||||
|
||||
import javax.validation.GroupSequence;
|
||||
|
||||
/**
|
||||
* 定义校验顺序,如果AddGroup组失败,则UpdateGroup组不会再校验
|
||||
*
|
||||
*
|
||||
*/
|
||||
@GroupSequence({AddGroup.class, UpdateGroup.class})
|
||||
public interface Group {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
|
||||
package com.zcloud.common.validator.group;
|
||||
|
||||
/**
|
||||
* 腾讯云
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface QcloudGroup {
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
|
||||
package com.zcloud.common.validator.group;
|
||||
|
||||
/**
|
||||
* 七牛
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface QiniuGroup {
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.zcloud.common.validator.group;
|
||||
|
||||
/**
|
||||
* 更新数据 Group
|
||||
*/
|
||||
|
||||
public interface UpdateGroup {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.zcloud.common.wxpay;
|
||||
|
||||
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
|
||||
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/12/13 10:21
|
||||
*/
|
||||
@Component
|
||||
public class WxBeanUtils {
|
||||
@Resource
|
||||
private WxPayBean wxPayBean;
|
||||
|
||||
public CloseableHttpClient initHttpClient() {
|
||||
CloseableHttpClient httpClient;
|
||||
AutoUpdateCertificatesVerifier verifier;
|
||||
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(wxPayBean.getPrivateKey());
|
||||
|
||||
verifier = new AutoUpdateCertificatesVerifier(
|
||||
new WechatPay2Credentials(wxPayBean.getMchId(), new PrivateKeySigner(wxPayBean.getMchSerialNo(), merchantPrivateKey)),
|
||||
wxPayBean.getApiv3Key().getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
httpClient = WechatPayHttpClientBuilder.create()
|
||||
.withMerchant(wxPayBean.getMchId(), wxPayBean.getMchSerialNo(), merchantPrivateKey )
|
||||
.withValidator(new WechatPay2Validator(verifier))
|
||||
.build();
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.zcloud.common.wxpay;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/12/04 11:07
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "wxpay")
|
||||
@Component
|
||||
@Data
|
||||
public class WxPayBean {
|
||||
private String appId;
|
||||
private String mchId;
|
||||
private String mchSerialNo;
|
||||
private String apiv3Key;
|
||||
private String privateKey;
|
||||
private String httpProxyDomain;
|
||||
private String wxDomain;
|
||||
}
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
package com.zcloud.common.wxpay;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
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.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.InetAddress;
|
||||
import java.security.*;
|
||||
import java.util.*;
|
||||
/**
|
||||
* @author fangjiakai
|
||||
* @date 2023/12/04 11:45
|
||||
*/
|
||||
@Component
|
||||
public class WxPayUtil {
|
||||
@Resource
|
||||
private WxPayBean wxPayBean;
|
||||
@Resource
|
||||
private WxBeanUtils wxBeanUtils;
|
||||
|
||||
public String pay(String outTradeNo, String totalAmount,String subject,String userAgent) throws Exception{
|
||||
CloseableHttpClient httpClient = /*wxBeanUtils.initHttpClient();*/ HttpClients.createDefault();
|
||||
HttpPost httpPost;
|
||||
if(userAgent.contains("Windows")){
|
||||
httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/h5");
|
||||
}else{
|
||||
httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
|
||||
}
|
||||
|
||||
httpPost.addHeader("Accept", "application/json");
|
||||
httpPost.addHeader("Content-type","application/json; charset=utf-8");
|
||||
httpPost.addHeader("Authorization","WECHATPAY2-SHA256-RSA2048");
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
ObjectNode rootNode = objectMapper.createObjectNode();
|
||||
rootNode.put("mchid", wxPayBean.getMchId())
|
||||
.put("appid", wxPayBean.getAppId())
|
||||
.put("description", "Image形象店-深圳腾大-QQ公仔")
|
||||
.put("subject", subject)
|
||||
.put("notify_url", "https://www.weixin.qq.com/wxpay/pay.php")
|
||||
.put("out_trade_no", outTradeNo);
|
||||
rootNode.putObject("amount")
|
||||
.put("currency", "CNY")
|
||||
.put("total", 1);
|
||||
|
||||
objectMapper.writeValue(bos, rootNode);
|
||||
|
||||
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
|
||||
CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||
httpClient.close();
|
||||
|
||||
String bodyAsString = EntityUtils.toString(response.getEntity());
|
||||
System.out.println(bodyAsString);
|
||||
return bodyAsString;
|
||||
}
|
||||
|
||||
private String makeUUID(int len) {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换金额型到整型
|
||||
* @param money
|
||||
* @return
|
||||
*/
|
||||
private String moneyToIntegerStr(Double money){
|
||||
BigDecimal decimal = new BigDecimal(money);
|
||||
int amount = decimal.multiply(new BigDecimal(100))
|
||||
.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
|
||||
return String.valueOf(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前机器的ip
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
private String getLocalIp(){
|
||||
InetAddress ia=null;
|
||||
String localip = null;
|
||||
try {
|
||||
ia=ia.getLocalHost();
|
||||
localip=ia.getHostAddress();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return localip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建签名Sign
|
||||
*
|
||||
* @param key
|
||||
* @param parameters
|
||||
* @return
|
||||
*/
|
||||
private String createSign(SortedMap<String,String> parameters,String key){
|
||||
StringBuffer sb = new StringBuffer();
|
||||
Set es = parameters.entrySet();
|
||||
Iterator<?> it = es.iterator();
|
||||
while(it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry)it.next();
|
||||
String k = (String)entry.getKey();
|
||||
if(entry.getValue() != null || !"".equals(entry.getValue())) {
|
||||
String v = String.valueOf(entry.getValue());
|
||||
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
|
||||
sb.append(k + "=" + v + "&");
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append("key=" + key);
|
||||
String sign = MD5Encode(sb.toString()).toUpperCase();
|
||||
return sign;
|
||||
}
|
||||
|
||||
private String MD5Encode(String str) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.update(str.getBytes("UTF-8"));
|
||||
byte b[] = md.digest();
|
||||
|
||||
int i;
|
||||
|
||||
StringBuffer buf = new StringBuffer("");
|
||||
for (int offset = 0; offset < b.length; offset++) {
|
||||
i = b[offset];
|
||||
if (i < 0)
|
||||
i += 256;
|
||||
if (i < 16)
|
||||
buf.append("0");
|
||||
buf.append(Integer.toHexString(i));
|
||||
}
|
||||
str = buf.toString();
|
||||
System.out.println(str);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map转换为 Xml
|
||||
*
|
||||
* @return Xml
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String mapToXml(SortedMap<String, String> map) throws Exception {
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
//防止XXE攻击
|
||||
documentBuilderFactory.setXIncludeAware(false);
|
||||
documentBuilderFactory.setExpandEntityReferences(false);
|
||||
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
|
||||
org.w3c.dom.Document document = documentBuilder.newDocument();
|
||||
org.w3c.dom.Element root = document.createElement("xml");
|
||||
document.appendChild(root);
|
||||
for (String key: map.keySet()) {
|
||||
String value = map.get(key);
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
value = value.trim();
|
||||
org.w3c.dom.Element filed = document.createElement(key);
|
||||
filed.appendChild(document.createTextNode(value));
|
||||
root.appendChild(filed);
|
||||
}
|
||||
TransformerFactory tf = TransformerFactory.newInstance();
|
||||
Transformer transformer = tf.newTransformer();
|
||||
DOMSource source = new DOMSource(document);
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
StringWriter writer = new StringWriter();
|
||||
StreamResult result = new StreamResult(writer);
|
||||
transformer.transform(source, result);
|
||||
String output = writer.getBuffer().toString();
|
||||
try {
|
||||
writer.close();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Xml字符串转换为Map
|
||||
*
|
||||
* @param xmlStr
|
||||
* @return
|
||||
*/
|
||||
private Map<String,String> xmlStrToMap(String xmlStr){
|
||||
Map<String,String> map = new HashMap<String,String>();
|
||||
Document doc;
|
||||
try {
|
||||
doc = DocumentHelper.parseText(xmlStr);
|
||||
Element root = doc.getRootElement();
|
||||
List children = root.elements();
|
||||
if(children != null && children.size() > 0) {
|
||||
for(int i = 0; i < children.size(); i++) {
|
||||
Element child = (Element)children.get(i);
|
||||
map.put(child.getName(), child.getTextTrim());
|
||||
}
|
||||
}
|
||||
} catch (DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,530 @@
|
|||
package com.zcloud.common.xss;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* HTML filtering utility for protecting against XSS (Cross Site Scripting).
|
||||
*
|
||||
* This code is licensed LGPLv3
|
||||
*
|
||||
* This code is a Java port of the original work in PHP by Cal Hendersen.
|
||||
* http://code.iamcal.com/php/lib_filter/
|
||||
*
|
||||
* The trickiest part of the translation was handling the differences in regex handling
|
||||
* between PHP and Java. These resources were helpful in the process:
|
||||
*
|
||||
* http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html
|
||||
* http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php
|
||||
* http://www.regular-expressions.info/modifiers.html
|
||||
*
|
||||
* A note on naming conventions: instance variables are prefixed with a "v"; global
|
||||
* constants are in all caps.
|
||||
*
|
||||
* Sample use:
|
||||
* String input = ...
|
||||
* String clean = new HTMLFilter().filter( input );
|
||||
*
|
||||
* The class is not thread safe. Create a new instance if in doubt.
|
||||
*
|
||||
* If you find bugs or have suggestions on improvement (especially regarding
|
||||
* performance), please contact us. The latest version of this
|
||||
* source, and our contact details, can be found at http://xss-html-filter.sf.net
|
||||
*
|
||||
* @author Joseph O'Connell
|
||||
* @author Cal Hendersen
|
||||
* @author Michael Semb Wever
|
||||
*/
|
||||
public final class HTMLFilter {
|
||||
|
||||
/** regex flag union representing /si modifiers in php **/
|
||||
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
|
||||
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
|
||||
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
|
||||
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
|
||||
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
|
||||
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
|
||||
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
|
||||
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
|
||||
private static final Pattern P_END_ARROW = Pattern.compile("^>");
|
||||
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_AMP = Pattern.compile("&");
|
||||
private static final Pattern P_QUOTE = Pattern.compile("<");
|
||||
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
|
||||
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
|
||||
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
|
||||
|
||||
// @xxx could grow large... maybe use sesat's ReferenceMap
|
||||
private static final ConcurrentMap<String,Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
|
||||
private static final ConcurrentMap<String,Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();
|
||||
|
||||
/** set of allowed html elements, along with allowed attributes for each element **/
|
||||
private final Map<String, List<String>> vAllowed;
|
||||
/** counts of open tags for each (allowable) html element **/
|
||||
private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
|
||||
|
||||
/** html elements which must always be self-closing (e.g. "<img />") **/
|
||||
private final String[] vSelfClosingTags;
|
||||
/** html elements which must always have separate opening and closing tags (e.g. "<b></b>") **/
|
||||
private final String[] vNeedClosingTags;
|
||||
/** set of disallowed html elements **/
|
||||
private final String[] vDisallowed;
|
||||
/** attributes which should be checked for valid protocols **/
|
||||
private final String[] vProtocolAtts;
|
||||
/** allowed protocols **/
|
||||
private final String[] vAllowedProtocols;
|
||||
/** tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />") **/
|
||||
private final String[] vRemoveBlanks;
|
||||
/** entities allowed within html markup **/
|
||||
private final String[] vAllowedEntities;
|
||||
/** flag determining whether comments are allowed in input String. */
|
||||
private final boolean stripComment;
|
||||
private final boolean encodeQuotes;
|
||||
private boolean vDebug = false;
|
||||
/**
|
||||
* flag determining whether to try to make tags when presented with "unbalanced"
|
||||
* angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false,
|
||||
* unbalanced angle brackets will be html escaped.
|
||||
*/
|
||||
private final boolean alwaysMakeTags;
|
||||
|
||||
/** Default constructor.
|
||||
*
|
||||
*/
|
||||
public HTMLFilter() {
|
||||
vAllowed = new HashMap<>();
|
||||
|
||||
final ArrayList<String> a_atts = new ArrayList<String>();
|
||||
a_atts.add("href");
|
||||
a_atts.add("target");
|
||||
vAllowed.put("a", a_atts);
|
||||
|
||||
final ArrayList<String> img_atts = new ArrayList<String>();
|
||||
img_atts.add("src");
|
||||
img_atts.add("width");
|
||||
img_atts.add("height");
|
||||
img_atts.add("alt");
|
||||
vAllowed.put("img", img_atts);
|
||||
|
||||
final ArrayList<String> no_atts = new ArrayList<String>();
|
||||
vAllowed.put("b", no_atts);
|
||||
vAllowed.put("strong", no_atts);
|
||||
vAllowed.put("i", no_atts);
|
||||
vAllowed.put("em", no_atts);
|
||||
|
||||
vSelfClosingTags = new String[]{"img"};
|
||||
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
|
||||
vDisallowed = new String[]{};
|
||||
vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
|
||||
vProtocolAtts = new String[]{"src", "href"};
|
||||
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
|
||||
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
|
||||
stripComment = true;
|
||||
encodeQuotes = true;
|
||||
alwaysMakeTags = true;
|
||||
}
|
||||
|
||||
/** Set debug flag to true. Otherwise use default settings. See the default constructor.
|
||||
*
|
||||
* @param debug turn debug on with a true argument
|
||||
*/
|
||||
public HTMLFilter(final boolean debug) {
|
||||
this();
|
||||
vDebug = debug;
|
||||
|
||||
}
|
||||
|
||||
/** Map-parameter configurable constructor.
|
||||
*
|
||||
* @param conf map containing configuration. keys match field names.
|
||||
*/
|
||||
public HTMLFilter(final Map<String,Object> conf) {
|
||||
|
||||
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
|
||||
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
|
||||
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
|
||||
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
|
||||
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
|
||||
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
|
||||
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
|
||||
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
|
||||
|
||||
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
|
||||
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
|
||||
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
|
||||
vDisallowed = (String[]) conf.get("vDisallowed");
|
||||
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
|
||||
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
|
||||
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
|
||||
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
|
||||
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
|
||||
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
|
||||
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
vTagCounts.clear();
|
||||
}
|
||||
|
||||
private void debug(final String msg) {
|
||||
if (vDebug) {
|
||||
Logger.getAnonymousLogger().info(msg);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// my versions of some PHP library functions
|
||||
public static String chr(final int decimal) {
|
||||
return String.valueOf((char) decimal);
|
||||
}
|
||||
|
||||
public static String htmlSpecialChars(final String s) {
|
||||
String result = s;
|
||||
result = regexReplace(P_AMP, "&", result);
|
||||
result = regexReplace(P_QUOTE, """, result);
|
||||
result = regexReplace(P_LEFT_ARROW, "<", result);
|
||||
result = regexReplace(P_RIGHT_ARROW, ">", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
/**
|
||||
* given a user submitted input String, filter out any invalid or restricted
|
||||
* html.
|
||||
*
|
||||
* @param input text (i.e. submitted by a user) than may contain html
|
||||
* @return "clean" version of input, with only valid, whitelisted html elements allowed
|
||||
*/
|
||||
public String filter(final String input) {
|
||||
reset();
|
||||
String s = input;
|
||||
|
||||
debug("************************************************");
|
||||
debug(" INPUT: " + input);
|
||||
|
||||
s = escapeComments(s);
|
||||
debug(" escapeComments: " + s);
|
||||
|
||||
s = balanceHTML(s);
|
||||
debug(" balanceHTML: " + s);
|
||||
|
||||
s = checkTags(s);
|
||||
debug(" checkTags: " + s);
|
||||
|
||||
s = processRemoveBlanks(s);
|
||||
debug("processRemoveBlanks: " + s);
|
||||
|
||||
s = validateEntities(s);
|
||||
debug(" validateEntites: " + s);
|
||||
|
||||
debug("************************************************\n\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean isAlwaysMakeTags(){
|
||||
return alwaysMakeTags;
|
||||
}
|
||||
|
||||
public boolean isStripComments(){
|
||||
return stripComment;
|
||||
}
|
||||
|
||||
private String escapeComments(final String s) {
|
||||
final Matcher m = P_COMMENTS.matcher(s);
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
if (m.find()) {
|
||||
final String match = m.group(1); //(.*?)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String balanceHTML(String s) {
|
||||
if (alwaysMakeTags) {
|
||||
//
|
||||
// try and form html
|
||||
//
|
||||
s = regexReplace(P_END_ARROW, "", s);
|
||||
s = regexReplace(P_BODY_TO_END, "<$1>", s);
|
||||
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
|
||||
|
||||
} else {
|
||||
//
|
||||
// escape stray brackets
|
||||
//
|
||||
s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
|
||||
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
|
||||
|
||||
//
|
||||
// the last regexp causes '<>' entities to appear
|
||||
// (we need to do a lookahead assertion so that the last bracket can
|
||||
// be used in the next pass of the regexp)
|
||||
//
|
||||
s = regexReplace(P_BOTH_ARROWS, "", s);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String checkTags(String s) {
|
||||
Matcher m = P_TAGS.matcher(s);
|
||||
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
while (m.find()) {
|
||||
String replaceStr = m.group(1);
|
||||
replaceStr = processTag(replaceStr);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
s = buf.toString();
|
||||
|
||||
// these get tallied in processTag
|
||||
// (remember to reset before subsequent calls to filter method)
|
||||
for (String key : vTagCounts.keySet()) {
|
||||
for (int ii = 0; ii < vTagCounts.get(key); ii++) {
|
||||
s += "</" + key + ">";
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String processRemoveBlanks(final String s) {
|
||||
String result = s;
|
||||
for (String tag : vRemoveBlanks) {
|
||||
if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){
|
||||
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
|
||||
if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){
|
||||
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
|
||||
Matcher m = regex_pattern.matcher(s);
|
||||
return m.replaceAll(replacement);
|
||||
}
|
||||
|
||||
private String processTag(final String s) {
|
||||
// ending tags
|
||||
Matcher m = P_END_TAG.matcher(s);
|
||||
if (m.find()) {
|
||||
final String name = m.group(1).toLowerCase();
|
||||
if (allowed(name)) {
|
||||
if (!inArray(name, vSelfClosingTags)) {
|
||||
if (vTagCounts.containsKey(name)) {
|
||||
vTagCounts.put(name, vTagCounts.get(name) - 1);
|
||||
return "</" + name + ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// starting tags
|
||||
m = P_START_TAG.matcher(s);
|
||||
if (m.find()) {
|
||||
final String name = m.group(1).toLowerCase();
|
||||
final String body = m.group(2);
|
||||
String ending = m.group(3);
|
||||
|
||||
//debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
|
||||
if (allowed(name)) {
|
||||
String params = "";
|
||||
|
||||
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
|
||||
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
|
||||
final List<String> paramNames = new ArrayList<String>();
|
||||
final List<String> paramValues = new ArrayList<String>();
|
||||
while (m2.find()) {
|
||||
paramNames.add(m2.group(1)); //([a-z0-9]+)
|
||||
paramValues.add(m2.group(3)); //(.*?)
|
||||
}
|
||||
while (m3.find()) {
|
||||
paramNames.add(m3.group(1)); //([a-z0-9]+)
|
||||
paramValues.add(m3.group(3)); //([^\"\\s']+)
|
||||
}
|
||||
|
||||
String paramName, paramValue;
|
||||
for (int ii = 0; ii < paramNames.size(); ii++) {
|
||||
paramName = paramNames.get(ii).toLowerCase();
|
||||
paramValue = paramValues.get(ii);
|
||||
|
||||
// debug( "paramName='" + paramName + "'" );
|
||||
// debug( "paramValue='" + paramValue + "'" );
|
||||
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
|
||||
|
||||
if (allowedAttribute(name, paramName)) {
|
||||
if (inArray(paramName, vProtocolAtts)) {
|
||||
paramValue = processParamProtocol(paramValue);
|
||||
}
|
||||
params += " " + paramName + "=\"" + paramValue + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
if (inArray(name, vSelfClosingTags)) {
|
||||
ending = " /";
|
||||
}
|
||||
|
||||
if (inArray(name, vNeedClosingTags)) {
|
||||
ending = "";
|
||||
}
|
||||
|
||||
if (ending == null || ending.length() < 1) {
|
||||
if (vTagCounts.containsKey(name)) {
|
||||
vTagCounts.put(name, vTagCounts.get(name) + 1);
|
||||
} else {
|
||||
vTagCounts.put(name, 1);
|
||||
}
|
||||
} else {
|
||||
ending = " /";
|
||||
}
|
||||
return "<" + name + params + ending + ">";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// comments
|
||||
m = P_COMMENT.matcher(s);
|
||||
if (!stripComment && m.find()) {
|
||||
return "<" + m.group() + ">";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private String processParamProtocol(String s) {
|
||||
s = decodeEntities(s);
|
||||
final Matcher m = P_PROTOCOL.matcher(s);
|
||||
if (m.find()) {
|
||||
final String protocol = m.group(1);
|
||||
if (!inArray(protocol, vAllowedProtocols)) {
|
||||
// bad protocol, turn into local anchor link instead
|
||||
s = "#" + s.substring(protocol.length() + 1, s.length());
|
||||
if (s.startsWith("#//")) {
|
||||
s = "#" + s.substring(3, s.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String decodeEntities(String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
Matcher m = P_ENTITY.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.decode(match).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENTITY_UNICODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENCODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
s = validateEntities(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
private String validateEntities(final String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
// validate entities throughout the string
|
||||
Matcher m = P_VALID_ENTITIES.matcher(s);
|
||||
while (m.find()) {
|
||||
final String one = m.group(1); //([^&;]*)
|
||||
final String two = m.group(2); //(?=(;|&|$))
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return encodeQuotes(buf.toString());
|
||||
}
|
||||
|
||||
private String encodeQuotes(final String s){
|
||||
if(encodeQuotes){
|
||||
StringBuffer buf = new StringBuffer();
|
||||
Matcher m = P_VALID_QUOTES.matcher(s);
|
||||
while (m.find()) {
|
||||
final String one = m.group(1); //(>|^)
|
||||
final String two = m.group(2); //([^<]+?)
|
||||
final String three = m.group(3); //(<|$)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
return buf.toString();
|
||||
}else{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
private String checkEntity(final String preamble, final String term) {
|
||||
|
||||
return ";".equals(term) && isValidEntity(preamble)
|
||||
? '&' + preamble
|
||||
: "&" + preamble;
|
||||
}
|
||||
|
||||
private boolean isValidEntity(final String entity) {
|
||||
return inArray(entity, vAllowedEntities);
|
||||
}
|
||||
|
||||
private static boolean inArray(final String s, final String[] array) {
|
||||
for (String item : array) {
|
||||
if (item != null && item.equals(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean allowed(final String name) {
|
||||
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
|
||||
}
|
||||
|
||||
private boolean allowedAttribute(final String name, final String paramName) {
|
||||
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
|
||||
package com.zcloud.common.xss;
|
||||
|
||||
import com.zcloud.common.exception.ZException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
/**
|
||||
* SQL过滤
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SQLFilter {
|
||||
|
||||
/**
|
||||
* SQL注入过滤
|
||||
* @param str 待验证的字符串
|
||||
*/
|
||||
public static String sqlInject(String str){
|
||||
if(StringUtils.isBlank(str)){
|
||||
return null;
|
||||
}
|
||||
//去掉'|"|;|\字符
|
||||
str = StringUtils.replace(str, "'", "");
|
||||
str = StringUtils.replace(str, "\"", "");
|
||||
str = StringUtils.replace(str, ";", "");
|
||||
str = StringUtils.replace(str, "\\", "");
|
||||
|
||||
//转换成小写
|
||||
str = str.toLowerCase();
|
||||
|
||||
//非法字符
|
||||
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
|
||||
|
||||
//判断是否包含非法字符
|
||||
for(String keyword : keywords){
|
||||
if(str.indexOf(keyword) != -1){
|
||||
throw new ZException("包含非法字符");
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
|
||||
package com.zcloud.common.xss;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* XSS过滤
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class XssFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig config) throws ServletException {
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
|
||||
(HttpServletRequest) request);
|
||||
chain.doFilter(xssRequest, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
|
||||
package com.zcloud.common.xss;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* XSS过滤处理
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
//没被包装过的HttpServletRequest(特殊场景,需要自己过滤)
|
||||
HttpServletRequest orgRequest;
|
||||
//html过滤
|
||||
private final static HTMLFilter htmlFilter = new HTMLFilter();
|
||||
|
||||
public XssHttpServletRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
orgRequest = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
//非json类型,直接返回
|
||||
if(!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))){
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
//为空,直接返回
|
||||
String json = IOUtils.toString(super.getInputStream(), "utf-8");
|
||||
if (StringUtils.isBlank(json)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
//xss过滤
|
||||
json = xssEncode(json);
|
||||
final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8"));
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return bis.read();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter(String name) {
|
||||
String value = super.getParameter(xssEncode(name));
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
value = xssEncode(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameterValues(String name) {
|
||||
String[] parameters = super.getParameterValues(name);
|
||||
if (parameters == null || parameters.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
parameters[i] = xssEncode(parameters[i]);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String[]> getParameterMap() {
|
||||
Map<String,String[]> map = new LinkedHashMap<>();
|
||||
Map<String,String[]> parameters = super.getParameterMap();
|
||||
for (String key : parameters.keySet()) {
|
||||
String[] values = parameters.get(key);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = xssEncode(values[i]);
|
||||
}
|
||||
map.put(key, values);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
String value = super.getHeader(xssEncode(name));
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
value = xssEncode(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String xssEncode(String input) {
|
||||
return htmlFilter.filter(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最原始的request
|
||||
*/
|
||||
public HttpServletRequest getOrgRequest() {
|
||||
return orgRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最原始的request
|
||||
*/
|
||||
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
|
||||
if (request instanceof XssHttpServletRequestWrapper) {
|
||||
return ((XssHttpServletRequestWrapper) request).getOrgRequest();
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.zcloud.config;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.*;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
/**
|
||||
* 解决依赖代码冲突问题
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class ConflictHandlingConfig {
|
||||
/**
|
||||
* 解决springboot升到2.6.x之后,knife4j报错
|
||||
* 原文链接:https://gitee.com/xiaoym/knife4j/issues/I4JT89
|
||||
* @param wes the web endpoints supplier
|
||||
* @param ses the servlet endpoints supplier
|
||||
* @param ces the controller endpoints supplier
|
||||
* @param emt the endpoint media types
|
||||
* @param cep the cors properties
|
||||
* @param wep the web endpoints properties
|
||||
* @param env the environment
|
||||
* @return the web mvc endpoint handler mapping
|
||||
*/
|
||||
@Bean
|
||||
public WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping(WebEndpointsSupplier wes
|
||||
, ServletEndpointsSupplier ses, ControllerEndpointsSupplier ces, EndpointMediaTypes emt
|
||||
, CorsEndpointProperties cep, WebEndpointProperties wep, Environment env) {
|
||||
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
|
||||
Collection<ExposableWebEndpoint> webEndpoints = wes.getEndpoints();
|
||||
allEndpoints.addAll(webEndpoints);
|
||||
allEndpoints.addAll(ses.getEndpoints());
|
||||
allEndpoints.addAll(ces.getEndpoints());
|
||||
String basePath = wep.getBasePath();
|
||||
EndpointMapping endpointMapping = new EndpointMapping(basePath);
|
||||
boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(wep, env, basePath);
|
||||
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, emt
|
||||
, cep.toCorsConfiguration(), new EndpointLinksResolver(
|
||||
allEndpoints, basePath), shouldRegisterLinksMapping, null);
|
||||
}
|
||||
/**
|
||||
* shouldRegisterLinksMapping
|
||||
*
|
||||
* @param wep
|
||||
* @param env
|
||||
* @param basePath
|
||||
* @return
|
||||
*/
|
||||
private boolean shouldRegisterLinksMapping(WebEndpointProperties wep, Environment env, String basePath) {
|
||||
return wep.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(env).equals(ManagementPortType.DIFFERENT));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
|
||||
package com.zcloud.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**") // 所有接口
|
||||
.allowCredentials(true) // 是否发送 Cookie
|
||||
.allowedOriginPatterns("*") // 支持域
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法
|
||||
.allowedHeaders("*")
|
||||
.exposedHeaders("*");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.zcloud.config;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||
import lombok.Data;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.client.RestClientBuilder;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "elasticsearch")
|
||||
@Data
|
||||
public class ElasticsearchConfiguration {
|
||||
private String host;
|
||||
private int port;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 解析配置的字符串,转为HttpHost对象数组
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private HttpHost toHttpHost() {
|
||||
HttpHost httpHost = new HttpHost(host, port, "http");
|
||||
return httpHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步客户端
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public ElasticsearchClient clientBySync() throws Exception {
|
||||
ElasticsearchTransport transport = getElasticsearchTransport(username, password, toHttpHost());
|
||||
return new ElasticsearchClient(transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步客户端
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public ElasticsearchAsyncClient clientByAsync() throws Exception {
|
||||
ElasticsearchTransport transport = getElasticsearchTransport(username, password, toHttpHost());
|
||||
return new ElasticsearchAsyncClient(transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* 传输对象
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public ElasticsearchTransport getTransport() throws Exception {
|
||||
return getElasticsearchTransport(username, password, toHttpHost());
|
||||
}
|
||||
|
||||
|
||||
private static ElasticsearchTransport getElasticsearchTransport(String username, String passwd, HttpHost... hosts) {
|
||||
// 账号密码的配置
|
||||
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
||||
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, passwd));
|
||||
|
||||
RestClientBuilder.HttpClientConfigCallback callback = httpAsyncClientBuilder -> httpAsyncClientBuilder
|
||||
.setDefaultCredentialsProvider(credentialsProvider);
|
||||
|
||||
// 用builder创建RestClient对象
|
||||
RestClient client = RestClient
|
||||
.builder(hosts)
|
||||
.setHttpClientConfigCallback(callback)
|
||||
.build();
|
||||
return new RestClientTransport(client, new JacksonJsonpMapper());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
|
||||
package com.zcloud.config;
|
||||
|
||||
import com.zcloud.common.xss.XssFilter;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
/**
|
||||
* Filter配置
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class FilterConfig {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean shiroFilterRegistration() {
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||
registration.setFilter(new DelegatingFilterProxy("shiroFilter"));
|
||||
//该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
|
||||
registration.addInitParameter("targetFilterLifecycle", "true");
|
||||
registration.setEnabled(true);
|
||||
registration.setOrder(Integer.MAX_VALUE - 1);
|
||||
registration.addUrlPatterns("/*");
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean xssFilterRegistration() {
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
||||
registration.setFilter(new XssFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("xssFilter");
|
||||
registration.setOrder(Integer.MAX_VALUE);
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
|
||||
package com.zcloud.config;
|
||||
|
||||
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
||||
import com.google.code.kaptcha.util.Config;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
/**
|
||||
* 生成验证码配置
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class KaptchaConfig {
|
||||
|
||||
@Bean
|
||||
public DefaultKaptcha producer() {
|
||||
Properties properties = new Properties();
|
||||
properties.put("kaptcha.border", "no");
|
||||
properties.put("kaptcha.textproducer.font.color", "black");
|
||||
properties.put("kaptcha.textproducer.char.space", "5");
|
||||
properties.put("kaptcha.textproducer.font.names", "Arial,Courier,cmr10,宋体,楷体,微软雅黑");
|
||||
Config config = new Config(properties);
|
||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||
defaultKaptcha.setConfig(config);
|
||||
return defaultKaptcha;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.zcloud.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.zcloud.modules.sys.plugins.YearTableNameHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* mybatis-plus配置
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
/**
|
||||
* 分页插件
|
||||
*/
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
|
||||
dynamicTableNameInnerInterceptor.setTableNameHandler(
|
||||
//可以传多个表名参数,指定哪些表使用MonthTableNameHandler处理表名称
|
||||
new YearTableNameHandler("sys_log")
|
||||
);
|
||||
//以拦截器的方式处理表名称
|
||||
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
|
||||
//可以传递多个拦截器,即:可以传递多个表名处理器TableNameHandler
|
||||
//interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
|
||||
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.zcloud.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.*;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* Redis配置
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
@Autowired
|
||||
private RedisConnectionFactory factory;
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate() {
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
|
||||
redisTemplate.setValueSerializer(new StringRedisSerializer());
|
||||
redisTemplate.setConnectionFactory(factory);
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForHash();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
|
||||
return redisTemplate.opsForValue();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForList();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForSet();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForZSet();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package com.zcloud.config;
|
||||
|
||||
import com.zcloud.modules.sys.oauth2.OAuth2Filter;
|
||||
import com.zcloud.modules.sys.oauth2.OAuth2Realm;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Shiro配置
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class ShiroConfig {
|
||||
|
||||
@Bean("securityManager")
|
||||
public SecurityManager securityManager(OAuth2Realm oAuth2Realm) {
|
||||
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
||||
securityManager.setRealm(oAuth2Realm);
|
||||
securityManager.setRememberMeManager(null);
|
||||
return securityManager;
|
||||
}
|
||||
|
||||
@Bean("shiroFilter")
|
||||
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
|
||||
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
|
||||
shiroFilter.setSecurityManager(securityManager);
|
||||
|
||||
//oauth过滤
|
||||
Map<String, Filter> filters = new HashMap<>();
|
||||
filters.put("oauth2", new OAuth2Filter());
|
||||
shiroFilter.setFilters(filters);
|
||||
|
||||
Map<String, String> filterMap = new LinkedHashMap<>();
|
||||
filterMap.put("/webjars/**", "anon");
|
||||
filterMap.put("/druid/**", "anon");
|
||||
filterMap.put("/app/**", "anon");
|
||||
filterMap.put("/public/**", "anon");
|
||||
filterMap.put("/sys/login", "anon");
|
||||
filterMap.put("/sys/dictionaries/list**", "anon");
|
||||
filterMap.put("/swagger/**", "anon");
|
||||
filterMap.put("/v2/api-docs", "anon");
|
||||
filterMap.put("/swagger-ui.html", "anon");
|
||||
filterMap.put("/swagger-resources/**", "anon");
|
||||
filterMap.put("/captcha.jpg", "anon");
|
||||
filterMap.put("/actuator/**", "anon");
|
||||
filterMap.put("/**", "oauth2");
|
||||
shiroFilter.setFilterChainDefinitionMap(filterMap);
|
||||
|
||||
return shiroFilter;
|
||||
}
|
||||
|
||||
@Bean("lifecycleBeanPostProcessor")
|
||||
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
|
||||
return new LifecycleBeanPostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
|
||||
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
|
||||
advisor.setSecurityManager(securityManager);
|
||||
return advisor;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue