shikeying
2022-09-27 26f5dd8ef80e5671cda8fc0e6c0d0298c4e678ff
视频相似度分析3
6个文件已添加
14个文件已修改
870 ■■■■■ 已修改文件
deploy-jar-template/pom.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
deploy-jar-template/src/main/resources/application-dev.yml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
deploy-jar-template/src/main/resources/application.yml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-common/src/main/java/com/iplatform/reccommon/TaskStatus.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-model-pojo/src/main/java/com/iplatform/model/po/Rc_video_batch.java 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-model-pojo/src/main/java/com/iplatform/model/po/Rc_video_batch_mapper.java 263 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-model-pojo/src/main/java/com/iplatform/model/po/Rc_video_user.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-model-pojo/src/main/java/com/iplatform/model/po/Rc_video_user_mapper.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/doc/table.SQL 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/SimilarExecutor.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/SimilarVideoInfo.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/SimilarVideoUser.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/api/DemoDebug.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/config/VideoSimilarProperties.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/controller/VideoResultController.java 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/scheduler/VideoSearchScheduler.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/scheduler/VideoSearchTask.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/java/com/iplatform/recvideo/service/VideoShowServiceImpl.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
recommend-video/src/main/resources/templates/video/index.ftl 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
deploy-jar-template/pom.xml
@@ -33,6 +33,10 @@
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
    </dependencies>
deploy-jar-template/src/main/resources/application-dev.yml
@@ -12,7 +12,7 @@
    type: com.walker.jdbc.ds.DefaultDataSource
    hikari:
      minimum-idle: 5
      idle-timeout: 5000
      idle-timeout: 600000
      pool-name: databasePool_walker
      connection-timeout: 10000
      connection-test-query: select 1
@@ -88,11 +88,14 @@
  video:
    # 视频采集存储根路径
#    data-folder: D:/dev_tools/ai/
    data-folder: /opt/ai/video/
    data-folder: D:/dev_tools/ai/
#    data-folder: /opt/ai/video/
    # 视频相似度AI服务URL
    ai-service: http://121.36.40.27:12345
    # 推荐相似视频(算法)前多少个
    top-n: 40
    # 测试模式,如果是则仅生成固定测试数据,正式部署需要改为 false
    test-mode: true
deploy-jar-template/src/main/resources/application.yml
@@ -1,3 +1,24 @@
spring:
  profiles:
    active: dev
  # 视频测试界面引入 2022-09-26
  freemarker:
    # 模板后缀名
    suffix: .ftl
    # 文档类型
    content-type: text/html
    # 页面编码
    charset: UTF-8
    # 页面缓存
    cache: false
    # 模板路径
    template-loader-path: classpath:/templates/
    settings:
      # 如果变量为null,转化为空字符串
      classic_compatible: true
      # 数字格式不用逗号隔开
      number_format: 0.##
      datetime_format: yyyy-MM-dd HH:mm:ss
      # 去掉多余的空格,非常有用
      whitespace_stripping: true
recommend-common/src/main/java/com/iplatform/reccommon/TaskStatus.java
New file
@@ -0,0 +1,44 @@
package com.iplatform.reccommon;
/**
 * 任务状态类型定义。
 * @author 时克英
 * @date 2022-09-27
 */
public enum TaskStatus {
    /**
     * 视频已被加载(解析)
     */
    VideoLoad{
        public String getIndex(){
            return INDEX_VIDEO_LOAD;
        }
    },
    /**
     * 视频已成功检索并生成相似视频(完毕)
     */
    VideoSearch{
        public String getIndex(){
            return INDEX_VIDEO_SEARCH;
        }
    };
    public String getIndex(){
        throw new AbstractMethodError();
    }
    public static final TaskStatus getType(String index){
        if(index.equals(INDEX_VIDEO_LOAD)){
            return VideoLoad;
        } else if(index.equals(INDEX_VIDEO_SEARCH)){
            return VideoSearch;
        } else {
            throw new UnsupportedOperationException("TaskStatus类型不支持: " + index);
        }
    }
    public static final String INDEX_VIDEO_LOAD = "0";
    public static final String INDEX_VIDEO_SEARCH = "1";
}
recommend-model-pojo/src/main/java/com/iplatform/model/po/Rc_video_batch.java
New file
@@ -0,0 +1,177 @@
package com.iplatform.model.po;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.walker.jdbc.BasePo;
/**
 * 表名:RC_VIDEO_BATCH *
 * @author genrator
 */
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class Rc_video_batch extends BasePo<Rc_video_batch> {
    // 序列化版本号
    private static final long serialVersionUID = 1L;
    /**
     * 用于兼容老写法
     */
    @JsonIgnore
    public static final Rc_video_batch ROW_MAPPER = new Rc_video_batch();
    // 主键
    private Long id = null;
    @JsonIgnore
    protected boolean isset_id = false;
    // 属性列表
    private String batch_id = null;
    @JsonIgnore
    protected boolean isset_batch_id = false;
    private Long user_id = null;
    @JsonIgnore
    protected boolean isset_user_id = false;
    private String src_video_id = null;
    @JsonIgnore
    protected boolean isset_src_video_id = false;
    private String src_video_path = null;
    @JsonIgnore
    protected boolean isset_src_video_path = false;
    /**
     * 默认构造函数
     */
    public Rc_video_batch() {
    }
    /**
     * 根据主键构造对象
     */
    public Rc_video_batch(Long id) {
        this.setId(id);
    }
    /**
     * 设置主键值
     */
    @Override
    public void setPkValue(Object value) {
        this.setId((Long) value);
    }
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
        this.isset_id = true;
    }
    @JsonIgnore
    public boolean isEmptyId() {
        return this.id == null;
    }
    public String getBatch_id() {
        return this.batch_id;
    }
    public void setBatch_id(String batch_id) {
        this.batch_id = batch_id;
        this.isset_batch_id = true;
    }
    @JsonIgnore
    public boolean isEmptyBatch_id() {
        return this.batch_id == null || this.batch_id.length() == 0;
    }
    public Long getUser_id() {
        return this.user_id;
    }
    public void setUser_id(Long user_id) {
        this.user_id = user_id;
        this.isset_user_id = true;
    }
    @JsonIgnore
    public boolean isEmptyUser_id() {
        return this.user_id == null;
    }
    public String getSrc_video_id() {
        return this.src_video_id;
    }
    public void setSrc_video_id(String src_video_id) {
        this.src_video_id = src_video_id;
        this.isset_src_video_id = true;
    }
    @JsonIgnore
    public boolean isEmptySrc_video_id() {
        return this.src_video_id == null || this.src_video_id.length() == 0;
    }
    public String getSrc_video_path() {
        return this.src_video_path;
    }
    public void setSrc_video_path(String src_video_path) {
        this.src_video_path = src_video_path;
        this.isset_src_video_path = true;
    }
    @JsonIgnore
    public boolean isEmptySrc_video_path() {
        return this.src_video_path == null || this.src_video_path.length() == 0;
    }
    /**
     * 重写 toString() 方法
     */
    @Override
    public String toString() {
        return new StringBuilder()
                .append("id=").append(this.id)
                .append("batch_id=").append(this.batch_id)
                .append("user_id=").append(this.user_id)
                .append("src_video_id=").append(this.src_video_id)
                .append("src_video_path=").append(this.src_video_path)
                .toString();
    }
    /**
     * 克隆
     */
    public Rc_video_batch $clone() {
        Rc_video_batch rc_video_batch = new Rc_video_batch();
        // 数据库名称
        //rc_video_batch.setDatabaseName_(this.getDatabaseName_());
        // 主键
        if (this.isset_id) {
            rc_video_batch.setId(this.getId());
        }
        // 普通属性
        if (this.isset_batch_id) {
            rc_video_batch.setBatch_id(this.getBatch_id());
        }
        if (this.isset_user_id) {
            rc_video_batch.setUser_id(this.getUser_id());
        }
        if (this.isset_src_video_id) {
            rc_video_batch.setSrc_video_id(this.getSrc_video_id());
        }
        if (this.isset_src_video_path) {
            rc_video_batch.setSrc_video_path(this.getSrc_video_path());
        }
        return rc_video_batch;
    }
}
recommend-model-pojo/src/main/java/com/iplatform/model/po/Rc_video_batch_mapper.java
New file
@@ -0,0 +1,263 @@
package com.iplatform.model.po;
import com.walker.jdbc.BaseMapper;
import com.walker.jdbc.ResultSetUtils;
import com.walker.jdbc.SqlAndParameters;
import com.walker.jdbc.sqlgen.DeleteBuilder;
import com.walker.jdbc.sqlgen.InsertBuilder;
import com.walker.jdbc.sqlgen.SelectBuilder;
import com.walker.jdbc.sqlgen.UpdateBuilder;
import com.walker.jdbc.util.StringUtils;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
/**
 * 表名:RC_VIDEO_BATCH *
 * @author genrator
 */
public class Rc_video_batch_mapper extends Rc_video_batch implements BaseMapper<Rc_video_batch> {
    // 序列化版本号
    private static final long serialVersionUID = 1L;
    public static final RowMapper<Rc_video_batch> ROW_MAPPER = new Rc_video_batchRowMapper();
    // 主键
    public static final String ID = "id";
    // 普通属性
    public static final String BATCH_ID = "batch_id";
    public static final String USER_ID = "user_id";
    public static final String SRC_VIDEO_ID = "src_video_id";
    public static final String SRC_VIDEO_PATH = "src_video_path";
    /**
     * 默认构造函数
     */
    public Rc_video_batch_mapper(Rc_video_batch rc_video_batch) {
        if (rc_video_batch == null) {
            throw new IllegalArgumentException("po参数不允许为空!");
        }
        //主键
        if (rc_video_batch.isset_id) {
            this.setId(rc_video_batch.getId());
        }
        //普通属性
        if (rc_video_batch.isset_batch_id) {
            this.setBatch_id(rc_video_batch.getBatch_id());
        }
        if (rc_video_batch.isset_user_id) {
            this.setUser_id(rc_video_batch.getUser_id());
        }
        if (rc_video_batch.isset_src_video_id) {
            this.setSrc_video_id(rc_video_batch.getSrc_video_id());
        }
        if (rc_video_batch.isset_src_video_path) {
            this.setSrc_video_path(rc_video_batch.getSrc_video_path());
        }
        // 去掉,2022-09-07
        // this.setDatabaseName_(rc_video_batch.getDatabaseName_());
    }
    /**
     * 获取表名
     */
    @Override
    public String getTableName_() {
        String tableName = "rc_video_batch";
        /**
        if (StringUtils.isNotEmpty(this.getDatabaseName_())) {
            return this.getDatabaseName_() + "." + tableName;
        } else {
            return tableName;
        }
        */
        return tableName;
    }
    /**
     * 获取主键名称
     */
    @Override
    public String getPkName_() {
        return ID;
    }
    /**
     * 获取主键值
     */
    @Override
    public Object getPkValue_() {
        return this.getId();
    }
    /**
     * 获取插入语句和参数
     */
    @Override
    public SqlAndParameters<Map<String, Object>> getInsertSql_() {
        InsertBuilder ib = new InsertBuilder(this.getTableName_());
        ib.set(ID, this.getId());
        ib.set(BATCH_ID, this.getBatch_id(), this.isset_batch_id);
        ib.set(USER_ID, this.getUser_id(), this.isset_user_id);
        ib.set(SRC_VIDEO_ID, this.getSrc_video_id(), this.isset_src_video_id);
        ib.set(SRC_VIDEO_PATH, this.getSrc_video_path(), this.isset_src_video_path);
        return ib.genMapSql();
    }
    /**
     * 获取更新语句和参数
     */
    @Override
    public SqlAndParameters<Map<String, Object>> getUpdateSql_() {
        UpdateBuilder ub = new UpdateBuilder(this.getTableName_());
        ub.set(BATCH_ID, this.getBatch_id(), this.isset_batch_id);
        ub.set(USER_ID, this.getUser_id(), this.isset_user_id);
        ub.set(SRC_VIDEO_ID, this.getSrc_video_id(), this.isset_src_video_id);
        ub.set(SRC_VIDEO_PATH, this.getSrc_video_path(), this.isset_src_video_path);
        ub.where(this.getPkName_(), this.getPkValue_());
        return ub.genMapSql();
    }
    /**
     * 获取更新语句和参数
     */
    @Override
    public SqlAndParameters<Map<String, Object>> getUpdateSql_(String where, Map<String, Object> parameters) {
        UpdateBuilder ub = new UpdateBuilder(this.getTableName_());
        ub.set(BATCH_ID, this.getBatch_id(), this.isset_batch_id);
        ub.set(USER_ID, this.getUser_id(), this.isset_user_id);
        ub.set(SRC_VIDEO_ID, this.getSrc_video_id(), this.isset_src_video_id);
        ub.set(SRC_VIDEO_PATH, this.getSrc_video_path(), this.isset_src_video_path);
        return ub.genMapSql(where, parameters);
    }
    /**
     * 获取更新语句和参数
     */
    @Override
    public SqlAndParameters<Object[]> getUpdateSql_(String where, Object[] parameters) {
        UpdateBuilder ub = new UpdateBuilder(this.getTableName_());
        ub.set(BATCH_ID, this.getBatch_id(), this.isset_batch_id);
        ub.set(USER_ID, this.getUser_id(), this.isset_user_id);
        ub.set(SRC_VIDEO_ID, this.getSrc_video_id(), this.isset_src_video_id);
        ub.set(SRC_VIDEO_PATH, this.getSrc_video_path(), this.isset_src_video_path);
        return ub.genArraySql(where, parameters);
    }
    /**
     * 获取删除语句和参数
     */
    @Override
    public SqlAndParameters<Map<String, Object>> getDeleteSql_() {
        DeleteBuilder db = new DeleteBuilder(this.getTableName_());
        db.where(this.getPkName_(), this.getPkValue_());
        return db.genMapSql();
    }
    /**
     * 获取删除语句和参数
     */
    @Override
    public SqlAndParameters<Map<String, Object>> getDeleteSql_(String where, Map<String, Object> parameters) {
        DeleteBuilder db = new DeleteBuilder(this.getTableName_());
        return db.genMapSql(where, parameters);
    }
    /**
     * 获取删除语句和参数
     */
    @Override
    public SqlAndParameters<Object[]> getDeleteSql_(String where, Object[] parameters) {
        DeleteBuilder db = new DeleteBuilder(this.getTableName_());
        return db.genArraySql(where, parameters);
    }
    /**
     * 获取单行查询语句和参数
     */
    @Override
    public SqlAndParameters<Map<String, Object>> getSingleSql_() {
        SelectBuilder sb = new SelectBuilder(this.getTableName_());
        sb.where(this.getPkName_(), this.getPkValue_());
        return sb.genMapSql();
    }
    /**
     * 获取查询语句和参数
     */
    @Override
    public SqlAndParameters<Map<String, Object>> getSelectSql_(String where, Map<String, Object> parameters) {
        return new SqlAndParameters<>("select id, batch_id, user_id, src_video_id, src_video_path from " + this.getTableName_() + " " + where, parameters);
    }
    /**
     * 获取查询语句和参数
     */
    @Override
    public SqlAndParameters<Object[]> getSelectSql_(String where, Object[] parameters) {
        return new SqlAndParameters<>("select id, batch_id, user_id, src_video_id, src_video_path from " + this.getTableName_() + " " + where, parameters);
    }
    /**
     * 将resultset的一行转化为po
     */
    @Override
    public Rc_video_batch mapRow(ResultSet rs, int i) throws SQLException {
        return ROW_MAPPER.mapRow(rs, i);
    }
    /**
     * 克隆
     */
    public Rc_video_batch toRc_video_batch() {
        return super.$clone();
    }
}
/**
 * rc_video_batch RowMapper
 *
 * @author genrator
 */
class Rc_video_batchRowMapper implements RowMapper<Rc_video_batch> {
    @Override
    public Rc_video_batch mapRow(ResultSet rs, int i) throws SQLException {
        ResultSetUtils resultSetUtils = new ResultSetUtils();
        Rc_video_batch rc_video_batch = new Rc_video_batch();
        Integer columnIndex;
        //主键
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_batch_mapper.ID);
        if (columnIndex > 0) {
            rc_video_batch.setId(rs.getLong(columnIndex));
        }
        //普通属性
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_batch_mapper.BATCH_ID);
        if (columnIndex > 0) {
            rc_video_batch.setBatch_id(rs.getString(columnIndex));
        }
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_batch_mapper.USER_ID);
        if (columnIndex > 0) {
            if (rs.getBigDecimal(columnIndex) == null) {
                rc_video_batch.setUser_id(null);
            } else {
                rc_video_batch.setUser_id(rs.getLong(columnIndex));
            }
        }
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_batch_mapper.SRC_VIDEO_ID);
        if (columnIndex > 0) {
            rc_video_batch.setSrc_video_id(rs.getString(columnIndex));
        }
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_batch_mapper.SRC_VIDEO_PATH);
        if (columnIndex > 0) {
            rc_video_batch.setSrc_video_path(rs.getString(columnIndex));
        }
        return rc_video_batch;
    }
}
recommend-model-pojo/src/main/java/com/iplatform/model/po/Rc_video_user.java
@@ -20,7 +20,7 @@
    public static final Rc_video_user ROW_MAPPER = new Rc_video_user();
    // 主键
    private Long id;
    private Long id = null;
    @JsonIgnore
    protected boolean isset_id = false;
@@ -62,7 +62,9 @@
        this.setId((Long) value);
    }
    public Long getId(){return this.id;}
    public Long getId() {
        return this.id;
    }
    public void setId(Long id){
        this.id = id;
@@ -136,6 +138,7 @@
    @Override
    public String toString() {
        return new StringBuilder()
                .append("id=").append(this.id)
                .append("user_id=").append(this.user_id)
                .append("video_id=").append(this.video_id)
                .append("score=").append(this.score)
@@ -153,10 +156,13 @@
        //rc_video_user.setDatabaseName_(this.getDatabaseName_());
        // 主键
        if (this.isset_id) {
            rc_video_user.setId(this.getId());
        }
        // 普通属性
        if (this.isset_user_id) {
            rc_video_user.setUser_id(this.getUser_id());
        }
        // 普通属性
        if (this.isset_video_id) {
            rc_video_user.setVideo_id(this.getVideo_id());
        }
recommend-model-pojo/src/main/java/com/iplatform/model/po/Rc_video_user_mapper.java
@@ -26,8 +26,9 @@
    public static final RowMapper<Rc_video_user> ROW_MAPPER = new Rc_video_userRowMapper();
    // 主键
    public static final String USER_ID = "user_id";
    public static final String ID = "id";
    // 普通属性
    public static final String USER_ID = "user_id";
    public static final String VIDEO_ID = "video_id";
    public static final String SCORE = "score";
    public static final String CREATE_TIME = "create_time";
@@ -40,10 +41,13 @@
            throw new IllegalArgumentException("po参数不允许为空!");
        }
        //主键
        if (rc_video_user.isset_id) {
            this.setId(rc_video_user.getId());
        }
        //普通属性
        if (rc_video_user.isset_user_id) {
            this.setUser_id(rc_video_user.getUser_id());
        }
        //普通属性
        if (rc_video_user.isset_video_id) {
            this.setVideo_id(rc_video_user.getVideo_id());
        }
@@ -78,7 +82,7 @@
     */
    @Override
    public String getPkName_() {
        return USER_ID;
        return ID;
    }
    /**
@@ -86,7 +90,7 @@
     */
    @Override
    public Object getPkValue_() {
        return this.getUser_id();
        return this.getId();
    }
    /**
@@ -95,7 +99,8 @@
    @Override
    public SqlAndParameters<Map<String, Object>> getInsertSql_() {
        InsertBuilder ib = new InsertBuilder(this.getTableName_());
        ib.set(USER_ID, this.getUser_id());
        ib.set(ID, this.getId());
        ib.set(USER_ID, this.getUser_id(), this.isset_user_id);
        ib.set(VIDEO_ID, this.getVideo_id(), this.isset_video_id);
        ib.set(SCORE, this.getScore(), this.isset_score);
        ib.set(CREATE_TIME, this.getCreate_time(), this.isset_create_time);
@@ -108,6 +113,7 @@
    @Override
    public SqlAndParameters<Map<String, Object>> getUpdateSql_() {
        UpdateBuilder ub = new UpdateBuilder(this.getTableName_());
        ub.set(USER_ID, this.getUser_id(), this.isset_user_id);
        ub.set(VIDEO_ID, this.getVideo_id(), this.isset_video_id);
        ub.set(SCORE, this.getScore(), this.isset_score);
        ub.set(CREATE_TIME, this.getCreate_time(), this.isset_create_time);
@@ -121,6 +127,7 @@
    @Override
    public SqlAndParameters<Map<String, Object>> getUpdateSql_(String where, Map<String, Object> parameters) {
        UpdateBuilder ub = new UpdateBuilder(this.getTableName_());
        ub.set(USER_ID, this.getUser_id(), this.isset_user_id);
        ub.set(VIDEO_ID, this.getVideo_id(), this.isset_video_id);
        ub.set(SCORE, this.getScore(), this.isset_score);
        ub.set(CREATE_TIME, this.getCreate_time(), this.isset_create_time);
@@ -134,6 +141,7 @@
    @Override
    public SqlAndParameters<Object[]> getUpdateSql_(String where, Object[] parameters) {
        UpdateBuilder ub = new UpdateBuilder(this.getTableName_());
        ub.set(USER_ID, this.getUser_id(), this.isset_user_id);
        ub.set(VIDEO_ID, this.getVideo_id(), this.isset_video_id);
        ub.set(SCORE, this.getScore(), this.isset_score);
        ub.set(CREATE_TIME, this.getCreate_time(), this.isset_create_time);
@@ -185,7 +193,7 @@
     */
    @Override
    public SqlAndParameters<Map<String, Object>> getSelectSql_(String where, Map<String, Object> parameters) {
        return new SqlAndParameters<>("select user_id, video_id, score, create_time from " + this.getTableName_() + " " + where, parameters);
        return new SqlAndParameters<>("select id, user_id, video_id, score, create_time from " + this.getTableName_() + " " + where, parameters);
    }
    /**
@@ -193,7 +201,7 @@
     */
    @Override
    public SqlAndParameters<Object[]> getSelectSql_(String where, Object[] parameters) {
        return new SqlAndParameters<>("select user_id, video_id, score, create_time from " + this.getTableName_() + " " + where, parameters);
        return new SqlAndParameters<>("select id, user_id, video_id, score, create_time from " + this.getTableName_() + " " + where, parameters);
    }
    /**
@@ -225,11 +233,19 @@
        Rc_video_user rc_video_user = new Rc_video_user();
        Integer columnIndex;
        //主键
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_user_mapper.USER_ID);
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_user_mapper.ID);
        if (columnIndex > 0) {
            rc_video_user.setUser_id(rs.getLong(columnIndex));
            rc_video_user.setId(rs.getLong(columnIndex));
        }
        //普通属性
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_user_mapper.USER_ID);
        if (columnIndex > 0) {
            if (rs.getBigDecimal(columnIndex) == null) {
                rc_video_user.setUser_id(null);
            } else {
                rc_video_user.setUser_id(rs.getLong(columnIndex));
            }
        }
        columnIndex = resultSetUtils.findColumn(rs, Rc_video_user_mapper.VIDEO_ID);
        if (columnIndex > 0) {
            rc_video_user.setVideo_id(rs.getString(columnIndex));
recommend-video/doc/table.SQL
@@ -15,3 +15,6 @@
ALTER TABLE rc_video_batch
    ADD INDEX inx_vb_bid (batch_id) USING BTREE ;
ALTER TABLE rc_video_user
    ADD INDEX inx_vu_uid (user_id) USING BTREE ;
recommend-video/pom.xml
@@ -40,6 +40,12 @@
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- FreeMarker做测试页面,2022/09/23 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
recommend-video/src/main/java/com/iplatform/recvideo/SimilarExecutor.java
@@ -8,7 +8,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
recommend-video/src/main/java/com/iplatform/recvideo/SimilarVideoInfo.java
@@ -1,6 +1,6 @@
package com.iplatform.recvideo;
import java.text.DecimalFormat;
import com.walker.infrastructure.utils.NumberFormatUtils;
/**
 * 相似视频对象定义。
@@ -18,7 +18,7 @@
    private double score = 0;
    private DecimalFormat df = new DecimalFormat("#.00");
//    private DecimalFormat df = new DecimalFormat("#.00");
    public String getId() {
        return id;
@@ -45,8 +45,9 @@
            return 0;
        }
        double s = (this.count)/100.0;
        String score = df.format(s);
        this.score = Double.parseDouble(score);
//        String score = df.format(s);
//        this.score = Double.parseDouble(score);
        this.score = NumberFormatUtils.scaleAccuracy2(s);
        return this.score;
    }
recommend-video/src/main/java/com/iplatform/recvideo/SimilarVideoUser.java
@@ -1,5 +1,7 @@
package com.iplatform.recvideo;
import com.walker.infrastructure.utils.NumberFormatUtils;
public class SimilarVideoUser implements Comparable<SimilarVideoUser>{
    private long userId;
@@ -32,7 +34,7 @@
    }
    public double getScore() {
        return score;
        return NumberFormatUtils.scaleAccuracy2(this.score);
    }
    @Override
recommend-video/src/main/java/com/iplatform/recvideo/api/DemoDebug.java
@@ -1,12 +1,19 @@
package com.iplatform.recvideo.api;
import com.iplatform.core.BeanContextAware;
import com.iplatform.recvideo.config.VideoSimilarProperties;
import com.iplatform.recvideo.scheduler.VideoSearchScheduler;
import com.iplatform.recvideo.service.VideoExecutorServiceImpl;
import com.iplatform.recvideo.support.DefaultSimilarExecutor;
import com.walker.scheduler.ScheduleEngine;
import com.walker.scheduler.util.OptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/debug/video")
@@ -15,6 +22,8 @@
    private RestTemplate restTemplate;
    private VideoSimilarProperties videoSimilarProperties;
    private VideoExecutorServiceImpl videoExecutorService;
    private VideoSearchScheduler videoSearchScheduler = null;
    private DefaultSimilarExecutor similarExecutor = null;
@@ -27,6 +36,25 @@
        this.videoExecutorService = videoExecutorService;
    }
    @RequestMapping("/start_scheduler_1")
    public String testStartVideoSearchScheduler(){
        if(this.videoSearchScheduler != null){
            this.videoSearchScheduler.stop();
            this.videoSearchScheduler = null;
        }
        List<Integer[]> timeRanges = new ArrayList<Integer[]>(1);
        timeRanges.add(new Integer[]{10,11});
        timeRanges.add(new Integer[]{12,12});
        this.videoSearchScheduler = new VideoSearchScheduler(100, "视频相似度分析调度任务");
        this.videoSearchScheduler.setOption(OptionUtils.combineEveryDayHourRange(timeRanges));
        this.videoSearchScheduler.setScheduleEngine(BeanContextAware.getBeanByType(ScheduleEngine.class));
        this.videoSearchScheduler.setMaxFailedTimes(10);
        this.videoSearchScheduler.start();
        return this.videoSearchScheduler.getName() + " 启动";
    }
    /**
     * 该测试用于模拟调度任务,每次调用一次执行器方法,批量处理一张图片数据。<p></p>
     * 最终完成一批多个视频的相似度检索并写入数据库中。
recommend-video/src/main/java/com/iplatform/recvideo/config/VideoSimilarProperties.java
@@ -11,6 +11,17 @@
    private String aiService;
    private boolean testMode = false;
    public boolean isTestMode() {
        return testMode;
    }
    public void setTestMode(boolean testMode) {
        this.testMode = testMode;
    }
    public String getAiService() {
        return aiService;
    }
recommend-video/src/main/java/com/iplatform/recvideo/controller/VideoResultController.java
New file
@@ -0,0 +1,137 @@
package com.iplatform.recvideo.controller;
import com.iplatform.model.po.Rc_video_batch;
import com.iplatform.model.po.Rc_video_t2;
import com.iplatform.recvideo.config.VideoSimilarProperties;
import com.iplatform.recvideo.service.VideoShowServiceImpl;
import com.walker.db.page.GenericPager;
import com.walker.infrastructure.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Controller
@RequestMapping("/video_ui")
public class VideoResultController {
    private VideoShowServiceImpl videoShowService;
    private VideoSimilarProperties videoSimilarProperties;
    @Autowired
    public VideoResultController(VideoShowServiceImpl videoShowService, VideoSimilarProperties videoSimilarProperties){
        this.videoShowService = videoShowService;
        this.videoSimilarProperties = videoSimilarProperties;
    }
    @GetMapping("/index")
    public String index(Model model, String id) {
        GenericPager<Rc_video_batch> pager = this.videoShowService.queryPageVideoBatchList();
        List<Rc_video_batch> data = pager.getDatas();
        model.addAttribute("src_list", data);
        model.addAttribute("video_folder", this.videoSimilarProperties.getDataFolder());
        if(StringUtils.isNotEmpty(id)){
            List<Rc_video_t2> list = this.videoShowService.querySimilarVideoList(id);
            model.addAttribute("similar_list", list);
            model.addAttribute("select_id", id);
        } else {
            model.addAttribute("select_id", null);
        }
        return "video/index";
    }
    /**
     * 本地视频转视频流流
     * @param response
     * @return
     */
    @RequestMapping("/get_video")
    @ResponseBody
    public void getVideo(
//            HttpServletRequest request,
            HttpServletResponse response, String id) {
        if(StringUtils.isEmpty(id)){
            System.out.println("视频ID未提供");
            return;
        }
        //视频资源存储信息
        response.reset();
        //获取从那个字节开始读取文件
//        String rangeString = request.getHeader("Range");
        String rangeString = null;
        Rc_video_batch videoInfo = this.videoShowService.queryOneVideoInfo(id);
        if(videoInfo == null){
            System.out.println("Rc_video_batch未查找到对象: " + id);
            return;
        }
        String videoPath = videoInfo.getSrc_video_path();
        if(this.videoSimilarProperties.isTestMode()){
            // 测试模式,需要替换文件根路径为本机windows路径
            StringBuilder windowPath = new StringBuilder(this.videoSimilarProperties.getDataFolder());
            windowPath.append(videoInfo.getBatch_id());
            windowPath.append("/").append(id).append(".mp4");
            videoPath = windowPath.toString();
        }
        try {
            //获取响应的输出流
            OutputStream outputStream = response.getOutputStream();
//            File file = new File("c:\\video.mp4");
            File file = new File(videoPath);
            if(file.exists()){
                RandomAccessFile targetFile = new RandomAccessFile(file, "r");
                long fileLength = targetFile.length();
                //播放
                if(rangeString != null){
                    long range = Long.valueOf(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
                    //设置内容类型
                    response.setHeader("Content-Type", "video/mp4");
                    //设置此次相应返回的数据长度
                    response.setHeader("Content-Length", String.valueOf(fileLength - range));
                    //设置此次相应返回的数据范围
                    response.setHeader("Content-Range", "bytes "+range+"-"+(fileLength-1)+"/"+fileLength);
                    //返回码需要为206,而不是200
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                    //设定文件读取开始位置(以字节为单位)
//                    targetFile.seek(range);
                }else {//下载
                    //设置响应头,把文件名字设置好
                    response.setHeader("Content-Disposition", "attachment; filename=video.mp4" );
                    //设置文件长度
                    response.setHeader("Content-Length", String.valueOf(fileLength));
                    //解决编码问题
                    response.setHeader("Content-Type","application/octet-stream");
                }
                byte[] cache = new byte[1024 * 300];
                int flag;
                while ((flag = targetFile.read(cache))!=-1){
                    outputStream.write(cache, 0, flag);
                }
            }else {
                String message = "file: not exists";
                //解决编码问题
                response.setHeader("Content-Type","application/json");
                outputStream.write(message.getBytes(StandardCharsets.UTF_8));
            }
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
recommend-video/src/main/java/com/iplatform/recvideo/scheduler/VideoSearchScheduler.java
@@ -49,11 +49,21 @@
            }
            logger.debug("开始启动批次查询:" + this.currentVideoSearchMeta.getBatchId());
        }
        if(this.currentVideoSearchMeta == null){
            // 说明上次已经创建 videoSearchTask 任务,但没有返回有效任务记录
            return null;
        }
        //
        this.videoSearchTask.checkExecutor(this.currentVideoSearchMeta);
        //
        int result = this.videoSearchTask.executeOneSearch();
        int result = 0;
        try{
            result = this.videoSearchTask.executeOneSearch();
        } catch (Exception ex){
            logger.error("executeOneSearch(): 执行异常:" + ex.getMessage(), ex);
            result = -1;
        }
        if(result == 0){
            return SUCCESS;
recommend-video/src/main/java/com/iplatform/recvideo/scheduler/VideoSearchTask.java
@@ -76,7 +76,7 @@
        defaultSimilarExecutor.setVideoExecutorService(BeanContextAware.getBeanByType(VideoExecutorServiceImpl.class));
        defaultSimilarExecutor.setRestTemplate(BeanContextAware.getBeanByType(RestTemplate.class));
        defaultSimilarExecutor.startup(this.videoSimilarProperties.getDataFolder()
                , videoSearchMeta.getBatchId(), this.videoSimilarProperties.getTopN(), true);
                , videoSearchMeta.getBatchId(), this.videoSimilarProperties.getTopN(), this.videoSimilarProperties.isTestMode());
        this.similarExecutor = defaultSimilarExecutor;
    }
recommend-video/src/main/java/com/iplatform/recvideo/service/VideoShowServiceImpl.java
New file
@@ -0,0 +1,39 @@
package com.iplatform.recvideo.service;
import com.iplatform.model.po.Rc_video_batch;
import com.iplatform.model.po.Rc_video_t2;
import com.walker.db.page.GenericPager;
import com.walker.jdbc.service.BaseServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class VideoShowServiceImpl extends BaseServiceImpl {
    /**
     * 返回部分原始视频集合,用于选择相似视频使用。
     * @return
     */
    public GenericPager<Rc_video_batch> queryPageVideoBatchList(){
        return this.selectSplit("select * from rc_video_batch", new Object[]{}, 1, 128, new Rc_video_batch());
    }
    /**
     * 返回给定原始视频,相似视频集合。
     * @param srcVideoId
     * @return
     */
    public List<Rc_video_t2> querySimilarVideoList(String srcVideoId){
        return this.select(new Rc_video_t2(), "where src_video_id=?", new Object[]{srcVideoId});
    }
    /**
     * 根据原始视频ID,查询该视频信息。
     * @param srcVideoId
     * @return
     */
    public Rc_video_batch queryOneVideoInfo(String srcVideoId){
        return this.get(new Rc_video_batch(), "where src_video_id=?", new Object[]{srcVideoId});
    }
}
recommend-video/src/main/resources/templates/video/index.ftl
New file
@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p> </p>
<table style="width: 90%;">
    <tr>
        <td style="width: 20%; vertical-align: top;"><h4>选择源视频:${select_id}<br></h4></td>
        <td style="width:10%;"></td>
        <td style="vertical-align: top;"><h4>相似视频集合</h4></td>
    </tr>
</table>
<table style="width: 90%;">
    <tr>
        <td style="width: 20%; vertical-align: top;">
            <table style="width: 90%;">
                <#list src_list as obj>
                    <tr>
                        <td>
                            <video id="my-video" class="video-js vjs-big-play-centered" controls="controls" poster="" width="320" height="180">
                                <source src="/video_ui/get_video?id=${obj.src_video_id}" type='video/mp4'>
                            </video>
                            <br> ${obj.src_video_id} <a href="/video_ui/index?id=${obj.src_video_id}">检索相似</a>
                            <p> </p>
                        </td>
                    </tr>
                </#list>
            </table>
        </td>
        <td style="width:10%;"></td>
        <td style="vertical-align: top;">
            <table style="width: 90%;">
                <#list similar_list as sim>
                    <tr>
                        <td>
                            <video id="my-video" class="video-js vjs-big-play-centered" controls="controls" poster="" width="320" height="180">
                                <source src="/video_ui/get_video?id=${sim.sim_video_id}" type='video/mp4'>
                            </video>
                            <br> ${sim.sim_video_id} 得分: ${sim.score}
                            <p> </p>
                        </td>
                    </tr>
                </#list>
            </table>
        </td>
    </tr>
</table>
</body>
</html>