This is an automated email from the ASF dual-hosted git repository.

dockerzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/inlong.git


The following commit(s) were added to refs/heads/master by this push:
     new 26927f526f [INLONG-10330][Manager] Support field template management 
(#10333)
26927f526f is described below

commit 26927f526f28f227cfb2224a10bd9d1fe042e075
Author: fuweng11 <[email protected]>
AuthorDate: Fri Jun 7 09:44:48 2024 +0800

    [INLONG-10330][Manager] Support field template management (#10333)
---
 .../inlong/manager/common/enums/ErrorCodeEnum.java |   8 +-
 .../common/enums/TemplateVisibleRange.java}        |  17 +-
 .../inlong/manager/dao/entity/TemplateEntity.java} |  31 ++-
 .../manager/dao/entity/TemplateFieldEntity.java}   |  33 ++-
 .../manager/dao/mapper/TemplateEntityMapper.java}  |  28 +-
 .../dao/mapper/TemplateFieldEntityMapper.java}     |  32 ++-
 .../resources/mappers/TemplateEntityMapper.xml     | 108 ++++++++
 .../mappers/TemplateFieldEntityMapper.xml          | 122 +++++++++
 .../inlong/manager/pojo/stream/TemplateField.java  | 117 +++++++++
 .../inlong/manager/pojo/stream/TemplateInfo.java   |  59 +++++
 .../manager/pojo/stream/TemplatePageRequest.java   |  62 +++++
 .../manager/pojo/stream/TemplateRequest.java       |  59 +++++
 .../manager/service/stream/TemplateService.java    |  83 ++++++
 .../service/stream/TemplateServiceImpl.java        | 287 +++++++++++++++++++++
 .../main/resources/h2/apache_inlong_manager.sql    |  41 +++
 .../manager-web/sql/apache_inlong_manager.sql      |  44 ++++
 inlong-manager/manager-web/sql/changes-1.13.0.sql  |  43 +++
 17 files changed, 1132 insertions(+), 42 deletions(-)

diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/ErrorCodeEnum.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/ErrorCodeEnum.java
index 98a7f50bd7..ed7549b699 100644
--- 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/ErrorCodeEnum.java
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/ErrorCodeEnum.java
@@ -162,9 +162,13 @@ public enum ErrorCodeEnum {
     MODULE_INFO_INCORRECT(6002, "Module info was incorrect"),
 
     PACKAGE_NOT_FOUND(7001, "Package does not exist/no operation authority"),
-    PACKAGE_INFO_INCORRECT(7002, "Package info was incorrect")
+    PACKAGE_INFO_INCORRECT(7002, "Package info was incorrect"),
 
-    ;
+    TEMPLATE_NOT_FOUND(8001, "Template does not exist/no operation authority"),
+    TEMPLATE_NAME_DUPLICATE(8002, "The current template name is exist"),
+    TEMPLATE_INFO_INCORRECT(8003, "Template info was incorrect"),
+    TEMPLATE_FIELD_UPDATE_NOT_ALLOWED(8004, "Current status not allowed to 
modification/delete field"),
+    TEMPLATE_PERMISSION_DENIED(8005, "No permission to this inlong template");
 
     private final int code;
     private final String message;
diff --git a/inlong-manager/manager-web/sql/changes-1.13.0.sql 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/TemplateVisibleRange.java
similarity index 57%
copy from inlong-manager/manager-web/sql/changes-1.13.0.sql
copy to 
inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/TemplateVisibleRange.java
index 7013c2990f..9b787b0c46 100644
--- a/inlong-manager/manager-web/sql/changes-1.13.0.sql
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/enums/TemplateVisibleRange.java
@@ -15,14 +15,15 @@
  * limitations under the License.
  */
 
--- This is the SQL change file from version 1.12.0 to the current version 
1.13.0.
--- When upgrading to version 1.13.0, please execute those SQLs in the DB (such 
as MySQL) used by the Manager module.
+package org.apache.inlong.manager.common.enums;
 
-SET NAMES utf8mb4;
-SET FOREIGN_KEY_CHECKS = 0;
+/**
+ * TemplateVisibleRange
+ */
+public enum TemplateVisibleRange {
 
-USE `apache_inlong_manager`;
+    ALL,
+    IN_CHARGE,
+    TENANT
 
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `username` varchar(256) DEFAULT 
NULL COMMENT 'username for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `password` varchar(256) DEFAULT 
NULL COMMENT 'password for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `ssh_port` int(11) DEFAULT NULL 
COMMENT 'ssh port';
+}
diff --git a/inlong-manager/manager-web/sql/changes-1.13.0.sql 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TemplateEntity.java
similarity index 57%
copy from inlong-manager/manager-web/sql/changes-1.13.0.sql
copy to 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TemplateEntity.java
index 7013c2990f..f9156ca190 100644
--- a/inlong-manager/manager-web/sql/changes-1.13.0.sql
+++ 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TemplateEntity.java
@@ -15,14 +15,29 @@
  * limitations under the License.
  */
 
--- This is the SQL change file from version 1.12.0 to the current version 
1.13.0.
--- When upgrading to version 1.13.0, please execute those SQLs in the DB (such 
as MySQL) used by the Manager module.
+package org.apache.inlong.manager.dao.entity;
 
-SET NAMES utf8mb4;
-SET FOREIGN_KEY_CHECKS = 0;
+import lombok.Data;
 
-USE `apache_inlong_manager`;
+import java.io.Serializable;
+import java.util.Date;
 
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `username` varchar(256) DEFAULT 
NULL COMMENT 'username for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `password` varchar(256) DEFAULT 
NULL COMMENT 'password for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `ssh_port` int(11) DEFAULT NULL 
COMMENT 'ssh port';
+/**
+ * Template entity, including name, etc.
+ */
+@Data
+public class TemplateEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    private Integer id;
+    private String name;
+    private String inCharges;
+    private String visibleRange;
+    private Integer isDeleted;
+    private String creator;
+    private String modifier;
+    private Date createTime;
+    private Date modifyTime;
+    private Integer version;
+
+}
diff --git a/inlong-manager/manager-web/sql/changes-1.13.0.sql 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TemplateFieldEntity.java
similarity index 53%
copy from inlong-manager/manager-web/sql/changes-1.13.0.sql
copy to 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TemplateFieldEntity.java
index 7013c2990f..22943711c4 100644
--- a/inlong-manager/manager-web/sql/changes-1.13.0.sql
+++ 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/entity/TemplateFieldEntity.java
@@ -15,14 +15,31 @@
  * limitations under the License.
  */
 
--- This is the SQL change file from version 1.12.0 to the current version 
1.13.0.
--- When upgrading to version 1.13.0, please execute those SQLs in the DB (such 
as MySQL) used by the Manager module.
+package org.apache.inlong.manager.dao.entity;
 
-SET NAMES utf8mb4;
-SET FOREIGN_KEY_CHECKS = 0;
+import lombok.Data;
 
-USE `apache_inlong_manager`;
+import java.io.Serializable;
 
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `username` varchar(256) DEFAULT 
NULL COMMENT 'username for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `password` varchar(256) DEFAULT 
NULL COMMENT 'password for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `ssh_port` int(11) DEFAULT NULL 
COMMENT 'ssh port';
+/**
+ * Template field entity, including template id, etc.
+ */
+@Data
+public class TemplateFieldEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    private Integer id;
+    private Integer templateId;
+    private Integer isPredefinedField;
+    private String fieldName;
+    private String fieldValue;
+    private String preExpression;
+    private String fieldType;
+    private String fieldComment;
+    private Integer isMetaField;
+    private String metaFieldName;
+    private String fieldFormat;
+    private Short rankNum;
+    private Integer isDeleted;
+
+}
diff --git a/inlong-manager/manager-web/sql/changes-1.13.0.sql 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TemplateEntityMapper.java
similarity index 57%
copy from inlong-manager/manager-web/sql/changes-1.13.0.sql
copy to 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TemplateEntityMapper.java
index 7013c2990f..16f13184e5 100644
--- a/inlong-manager/manager-web/sql/changes-1.13.0.sql
+++ 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TemplateEntityMapper.java
@@ -15,14 +15,26 @@
  * limitations under the License.
  */
 
--- This is the SQL change file from version 1.12.0 to the current version 
1.13.0.
--- When upgrading to version 1.13.0, please execute those SQLs in the DB (such 
as MySQL) used by the Manager module.
+package org.apache.inlong.manager.dao.mapper;
 
-SET NAMES utf8mb4;
-SET FOREIGN_KEY_CHECKS = 0;
+import org.apache.inlong.manager.dao.entity.TemplateEntity;
+import org.apache.inlong.manager.pojo.stream.TemplatePageRequest;
 
-USE `apache_inlong_manager`;
+import org.springframework.stereotype.Repository;
 
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `username` varchar(256) DEFAULT 
NULL COMMENT 'username for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `password` varchar(256) DEFAULT 
NULL COMMENT 'password for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `ssh_port` int(11) DEFAULT NULL 
COMMENT 'ssh port';
+import java.util.List;
+
+@Repository
+public interface TemplateEntityMapper {
+
+    int insert(TemplateEntity record);
+
+    TemplateEntity selectByPrimaryKey(Integer id);
+
+    TemplateEntity selectByName(String name);
+
+    List<TemplateEntity> selectByCondition(TemplatePageRequest request);
+
+    int updateByIdSelective(TemplateEntity record);
+
+}
diff --git a/inlong-manager/manager-web/sql/changes-1.13.0.sql 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TemplateFieldEntityMapper.java
similarity index 51%
copy from inlong-manager/manager-web/sql/changes-1.13.0.sql
copy to 
inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TemplateFieldEntityMapper.java
index 7013c2990f..fdb435be63 100644
--- a/inlong-manager/manager-web/sql/changes-1.13.0.sql
+++ 
b/inlong-manager/manager-dao/src/main/java/org/apache/inlong/manager/dao/mapper/TemplateFieldEntityMapper.java
@@ -15,14 +15,30 @@
  * limitations under the License.
  */
 
--- This is the SQL change file from version 1.12.0 to the current version 
1.13.0.
--- When upgrading to version 1.13.0, please execute those SQLs in the DB (such 
as MySQL) used by the Manager module.
+package org.apache.inlong.manager.dao.mapper;
 
-SET NAMES utf8mb4;
-SET FOREIGN_KEY_CHECKS = 0;
+import org.apache.inlong.manager.dao.entity.TemplateFieldEntity;
 
-USE `apache_inlong_manager`;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
 
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `username` varchar(256) DEFAULT 
NULL COMMENT 'username for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `password` varchar(256) DEFAULT 
NULL COMMENT 'password for ssh';
-ALTER TABLE `inlong_cluster_node` ADD COLUMN  `ssh_port` int(11) DEFAULT NULL 
COMMENT 'ssh port';
+import java.util.List;
+
+@Repository
+public interface TemplateFieldEntityMapper {
+
+    int insert(TemplateFieldEntity record);
+
+    int insertAll(@Param("fieldList") List<TemplateFieldEntity> 
fieldEntityList);
+
+    TemplateFieldEntity selectByPrimaryKey(Integer id);
+
+    List<TemplateFieldEntity> selectByTemplateId(@Param("templateId") Integer 
templateId);
+
+    int deleteByPrimaryKey(Integer id);
+
+    int logicDeleteAllByTemplateId(@Param("templateId") Integer templateId);
+
+    int deleteAllByTemplateId(@Param("templateId") Integer templateId);
+
+}
diff --git 
a/inlong-manager/manager-dao/src/main/resources/mappers/TemplateEntityMapper.xml
 
b/inlong-manager/manager-dao/src/main/resources/mappers/TemplateEntityMapper.xml
new file mode 100644
index 0000000000..9766c9c9d8
--- /dev/null
+++ 
b/inlong-manager/manager-dao/src/main/resources/mappers/TemplateEntityMapper.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements. See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership. The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd";>
+<mapper namespace="org.apache.inlong.manager.dao.mapper.TemplateEntityMapper">
+    <resultMap id="BaseResultMap" 
type="org.apache.inlong.manager.dao.entity.TemplateEntity">
+        <id column="id" jdbcType="INTEGER" property="id"/>
+        <result column="name" jdbcType="VARCHAR" property="name"/>
+        <result column="in_charges" jdbcType="VARCHAR" property="inCharges"/>
+        <result column="visible_range" jdbcType="VARCHAR" 
property="visibleRange"/>
+        <result column="is_deleted" jdbcType="INTEGER" property="isDeleted"/>
+        <result column="creator" jdbcType="VARCHAR" property="creator"/>
+        <result column="modifier" jdbcType="VARCHAR" property="modifier"/>
+        <result column="create_time" jdbcType="TIMESTAMP" 
property="createTime"/>
+        <result column="modify_time" jdbcType="TIMESTAMP" 
property="modifyTime"/>
+        <result column="version" jdbcType="INTEGER" property="version"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id, name, in_charges, visible_range, is_deleted, creator, modifier, 
create_time, modify_time, version
+    </sql>
+    <insert id="insert" useGeneratedKeys="true" keyProperty="id"
+            
parameterType="org.apache.inlong.manager.dao.entity.TemplateEntity">
+        insert into template (id, name, in_charges,
+                                    visible_range, creator, modifier)
+        values (#{id, jdbcType=INTEGER}, #{name, jdbcType=VARCHAR}, 
#{inCharges, jdbcType=VARCHAR},
+                #{visibleRange, jdbcType=VARCHAR}, #{creator, 
jdbcType=VARCHAR}, #{modifier, jdbcType=VARCHAR})
+    </insert>
+
+    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" 
resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from template
+        where id = #{id,jdbcType=INTEGER}
+        and is_deleted = 0
+    </select>
+    <select id="selectByName" parameterType="java.lang.String" 
resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from template
+        where name = #{name,jdbcType=VARCHAR}
+        and is_deleted = 0
+    </select>
+    <select id="selectByCondition"
+            
parameterType="org.apache.inlong.manager.pojo.stream.TemplatePageRequest"
+            resultType="org.apache.inlong.manager.dao.entity.TemplateEntity">
+        select
+        <include refid="Base_Column_List"/>
+        from template t
+        <where>
+            t.is_deleted = 0
+            <if test="name != null">
+                and t.name = #{name,jdbcType=VARCHAR}
+            </if>
+            <if test="inCharges != null">
+                and t.in_charges = #{inCharges,jdbcType=VARCHAR}
+            </if>
+            and (t.visible_range = "ALL" or
+            (t.visible_range = "IN_CHARGE"
+            and find_in_set(#{currentUser, jdbcType=VARCHAR}, t.in_charges))
+            )
+            <if test="visibleRange != null">
+                and t.visible_range = #{visibleRange,jdbcType=VARCHAR}
+            </if>
+        </where>
+        order by t.modify_time desc
+    </select>
+    <update id="updateByIdSelective" 
parameterType="org.apache.inlong.manager.dao.entity.TemplateEntity">
+        update template
+        <set>
+            <if test="name != null">
+                name = #{name,jdbcType=VARCHAR},
+            </if>
+            <if test="inCharges != null">
+                in_charges = #{inCharges,jdbcType=VARCHAR},
+            </if>
+            <if test="visibleRange != null">
+                visible_range = #{visibleRange,jdbcType=VARCHAR},
+            </if>
+            <if test="isDeleted != null">
+                is_deleted = #{isDeleted,jdbcType=INTEGER},
+            </if>
+            <if test="modifier != null">
+                modifier = #{modifier,jdbcType=VARCHAR},
+            </if>
+            version = #{version,jdbcType=INTEGER} + 1
+        </set>
+        where id = #{id,jdbcType=INTEGER}
+        and version = #{version,jdbcType=INTEGER}
+    </update>
+</mapper>
diff --git 
a/inlong-manager/manager-dao/src/main/resources/mappers/TemplateFieldEntityMapper.xml
 
b/inlong-manager/manager-dao/src/main/resources/mappers/TemplateFieldEntityMapper.xml
new file mode 100644
index 0000000000..c748704bba
--- /dev/null
+++ 
b/inlong-manager/manager-dao/src/main/resources/mappers/TemplateFieldEntityMapper.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements. See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership. The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd";>
+<mapper 
namespace="org.apache.inlong.manager.dao.mapper.TemplateFieldEntityMapper">
+    <resultMap id="BaseResultMap" 
type="org.apache.inlong.manager.dao.entity.TemplateFieldEntity">
+        <id column="id" jdbcType="INTEGER" property="id"/>
+        <result column="template_id" jdbcType="INTEGER" property="templateId"/>
+        <result column="is_predefined_field" jdbcType="INTEGER" 
property="isPredefinedField"/>
+        <result column="field_name" jdbcType="VARCHAR" property="fieldName"/>
+        <result column="field_value" jdbcType="VARCHAR" property="fieldValue"/>
+        <result column="pre_expression" jdbcType="VARCHAR" 
property="preExpression"/>
+        <result column="field_type" jdbcType="VARCHAR" property="fieldType"/>
+        <result column="field_comment" jdbcType="VARCHAR" 
property="fieldComment"/>
+        <result column="is_meta_field" jdbcType="SMALLINT" 
property="isMetaField"/>
+        <result column="meta_field_name" jdbcType="VARCHAR" 
property="metaFieldName"/>
+        <result column="field_format" jdbcType="VARCHAR" 
property="fieldFormat"/>
+        <result column="rank_num" jdbcType="INTEGER" property="rankNum"/>
+        <result column="is_deleted" jdbcType="INTEGER" property="isDeleted"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id, template_id, is_predefined_field, field_name, field_value, 
pre_expression,
+        field_type, field_comment, is_meta_field, meta_field_name, 
field_format, rank_num, is_deleted
+    </sql>
+    <insert id="insert" useGeneratedKeys="true" keyProperty="id"
+            
parameterType="org.apache.inlong.manager.dao.entity.TemplateFieldEntity">
+        insert into template_field (id, template_id,
+                                         is_predefined_field, field_name, 
field_value,
+                                         pre_expression, field_type, 
field_comment,
+                                         is_meta_field, meta_field_name, 
field_format,
+                                         rank_num, is_deleted)
+        values (#{id,jdbcType=INTEGER}, #{templateId,jdbcType=INTEGER},
+                #{isPredefinedField,jdbcType=INTEGER}, 
#{fieldName,jdbcType=VARCHAR}, #{fieldValue,jdbcType=VARCHAR},
+                #{preExpression,jdbcType=VARCHAR}, 
#{fieldType,jdbcType=VARCHAR}, #{fieldComment,jdbcType=VARCHAR},
+                #{isMetaField,jdbcType=SMALLINT}, 
#{metaFieldName,jdbcType=VARCHAR}, #{fieldFormat,jdbcType=VARCHAR},
+                #{rankNum,jdbcType=SMALLINT}, #{isDeleted,jdbcType=INTEGER})
+    </insert>
+    <!-- Bulk insert, update if it exists -->
+    <insert id="insertAll" parameterType="java.util.List">
+        insert into template_field (
+        id, template_id, is_predefined_field,
+        field_name, field_value, pre_expression, field_type,
+        field_comment, is_meta_field, meta_field_name, field_format,
+        rank_num, is_deleted
+        )
+        values
+        <foreach collection="fieldList" index="index" item="item" 
separator=",">
+            (
+            #{item.id}, #{item.templateId}, #{item.isPredefinedField},
+            #{item.fieldName}, #{item.fieldValue}, #{item.preExpression}, 
#{item.fieldType},
+            #{item.fieldComment}, #{item.isMetaField}, #{item.metaFieldName}, 
#{item.fieldFormat},
+            #{item.rankNum}, #{item.isDeleted}
+            )
+        </foreach>
+        ON DUPLICATE KEY UPDATE
+        id = values(id),
+        template_id = values(template_id),
+        is_predefined_field = values(is_predefined_field),
+        field_name = values(field_name),
+        field_value = values(field_value),
+        pre_expression = values(pre_expression),
+        field_type = values(field_type),
+        is_meta_field = values(is_meta_field),
+        meta_field_name = values(meta_field_name),
+        field_format = values(field_format),
+        field_comment = values(field_comment),
+        rank_num = values(rank_num),
+        is_deleted = values(is_deleted)
+    </insert>
+
+    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" 
resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from template_field
+        where id = #{id,jdbcType=INTEGER}
+    </select>
+    <select id="selectByTemplateId" 
resultType="org.apache.inlong.manager.dao.entity.TemplateFieldEntity">
+        select
+        <include refid="Base_Column_List"/>
+        from template_field
+        where template_id = #{templateId, jdbcType=INTEGER}
+        and is_deleted = 0
+        order by id asc
+    </select>
+
+    <update id="logicDeleteAllByTemplateId">
+        update template_field
+        set is_deleted = id
+        where template_id = #{templateId, jdbcType=INTEGER}
+          and is_deleted = 0
+    </update>
+
+    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
+        delete
+        from template_field
+        where id = #{id,jdbcType=INTEGER}
+    </delete>
+    <delete id="deleteAllByTemplateId">
+        delete
+        from template_field
+        where template_id = #{templateId, jdbcType=INTEGER}
+          and is_deleted = 0
+    </delete>
+</mapper>
diff --git 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateField.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateField.java
new file mode 100644
index 0000000000..1eef158969
--- /dev/null
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateField.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.pojo.stream;
+
+import org.apache.inlong.manager.common.tool.excel.annotation.ExcelEntity;
+import org.apache.inlong.manager.common.tool.excel.annotation.ExcelField;
+import org.apache.inlong.manager.common.tool.excel.annotation.Font;
+import org.apache.inlong.manager.common.tool.excel.annotation.Style;
+import 
org.apache.inlong.manager.common.tool.excel.validator.NonEmptyCellValidator;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import java.io.Serializable;
+
+/**
+ * Template filed, including field name, field type, etc.
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel("Template field configuration")
+@ExcelEntity(name = "InLong-Template-field")
+public class TemplateField implements Serializable {
+
+    @ApiModelProperty("Field index")
+    private Integer id;
+
+    @ExcelField(name = "Field name", validator = NonEmptyCellValidator.class, 
font = @Font(size = 16), style = @Style(bgColor = 
IndexedColors.LIGHT_TURQUOISE, width = 9000, allBorderColor = 
IndexedColors.BLUE, allBorderStyle = BorderStyle.THIN), headerFont = @Font(size 
= 20, color = IndexedColors.WHITE), headerStyle = @Style(bgColor = 
IndexedColors.DARK_BLUE, width = 9000, allBorderColor = IndexedColors.BLUE, 
allBorderStyle = BorderStyle.THIN))
+    @ApiModelProperty(value = "Field name", required = true)
+    private String fieldName;
+
+    @ExcelField(name = "Field type", validator = 
StreamFieldTypeCellValidator.class, font = @Font(size = 16), style = 
@Style(bgColor = IndexedColors.LIGHT_TURQUOISE, width = 6000, allBorderColor = 
IndexedColors.BLUE, allBorderStyle = BorderStyle.THIN), headerFont = @Font(size 
= 20, color = IndexedColors.WHITE), headerStyle = @Style(bgColor = 
IndexedColors.DARK_BLUE, width = 9000, allBorderColor = IndexedColors.BLUE, 
allBorderStyle = BorderStyle.THIN))
+    @ApiModelProperty(value = "Field type", required = true)
+    private String fieldType;
+
+    @ExcelField(name = "Field comment", font = @Font(size = 16), style = 
@Style(bgColor = IndexedColors.LIGHT_TURQUOISE, width = 10000, allBorderColor = 
IndexedColors.BLUE, allBorderStyle = BorderStyle.THIN), headerFont = @Font(size 
= 20, color = IndexedColors.WHITE), headerStyle = @Style(bgColor = 
IndexedColors.DARK_BLUE, width = 9000, allBorderColor = IndexedColors.BLUE, 
allBorderStyle = BorderStyle.THIN))
+    @ApiModelProperty("Field comment")
+    private String fieldComment;
+
+    @ApiModelProperty(value = "Is predefined field, 1: yes, 0: no")
+    private Integer isPredefinedField;
+
+    @ApiModelProperty(value = "Field value for constants")
+    private String fieldValue;
+
+    @ApiModelProperty(value = "Value expression of predefined field")
+    private String preExpression;
+
+    @ApiModelProperty("Is this field a meta field, 0: no, 1: yes, default is 
0")
+    @Builder.Default
+    private Integer isMetaField = 0;
+
+    @ApiModelProperty(value = "Meta field name")
+    private String metaFieldName;
+
+    @ApiModelProperty("Field format, including: MICROSECONDS, MILLISECONDS, 
SECONDS, SQL, ISO_8601"
+            + " and custom such as 'yyyy-MM-dd HH:mm:ss'. This is mainly used 
for time format")
+    private String fieldFormat;
+
+    @ApiModelProperty("Origin node name which stream fields belong")
+    private String originNodeName;
+
+    @ApiModelProperty("Origin field name before transform operation")
+    private String originFieldName;
+
+    @ApiModelProperty("Extra Param in JSON style")
+    private String extParams;
+
+    public TemplateField(int index, String fieldType, String fieldName, String 
fieldComment, String fieldValue) {
+        this.id = index;
+        this.fieldType = fieldType;
+        this.fieldName = fieldName;
+        this.fieldComment = fieldComment;
+        this.fieldValue = fieldValue;
+    }
+
+    public TemplateField(int index, String fieldType, String fieldName, String 
fieldComment, String fieldValue,
+            Integer isMetaField, String metaFieldName) {
+        this(index, fieldType, fieldName, fieldComment, fieldValue);
+        this.isMetaField = isMetaField;
+        this.metaFieldName = metaFieldName;
+    }
+    public TemplateField(int index, String fieldType, String fieldName, String 
fieldComment, String fieldValue,
+            Integer isMetaField, String metaFieldName, String originNodeName) {
+        this(index, fieldType, fieldName, fieldComment, fieldValue, 
isMetaField, metaFieldName);
+        this.originNodeName = originNodeName;
+    }
+    public TemplateField(int index, String fieldType, String fieldName, String 
fieldComment, String fieldValue,
+            Integer isMetaField, String metaFieldName, String originNodeName, 
String originFieldName) {
+        this(index, fieldType, fieldName, fieldComment, fieldValue, 
isMetaField, metaFieldName, originNodeName);
+        this.originFieldName = originFieldName;
+    }
+
+}
diff --git 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateInfo.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateInfo.java
new file mode 100644
index 0000000000..6e1d027c3d
--- /dev/null
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateInfo.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.pojo.stream;
+
+import org.apache.inlong.manager.common.validation.SaveValidation;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+import java.util.List;
+
+/**
+ * Inlong template info.
+ */
+@Data
+@ApiModel("Inlong template info")
+public class TemplateInfo {
+
+    @ApiModelProperty(value = "Primary key")
+    private Integer id;
+
+    @ApiModelProperty(value = "Template name")
+    @NotBlank(groups = SaveValidation.class, message = "template name cannot 
be blank")
+    private String name;
+
+    @ApiModelProperty(value = "Name of responsible person, separated by 
commas")
+    private String inCharges;
+
+    @ApiModelProperty(value = "Visible range for template")
+    private String visibleRange;
+
+    @ApiModelProperty(value = "Field list")
+    private List<TemplateField> fieldList;
+
+    @ApiModelProperty(value = "Bind tenants")
+    private List<String> tenantList;
+
+    @ApiModelProperty(value = "Version number")
+    private Integer version;
+
+}
diff --git 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplatePageRequest.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplatePageRequest.java
new file mode 100644
index 0000000000..0448eeaa5e
--- /dev/null
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplatePageRequest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.pojo.stream;
+
+import org.apache.inlong.manager.common.validation.SaveValidation;
+import org.apache.inlong.manager.pojo.common.PageRequest;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * Inlong template paging query conditions
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+@ApiModel("Inlong stream paging query request")
+public class TemplatePageRequest extends PageRequest {
+
+    @ApiModelProperty(value = "Template name")
+    @NotBlank(groups = SaveValidation.class, message = "template name cannot 
be blank")
+    private String name;
+
+    @ApiModelProperty(value = "Name of responsible person, separated by 
commas")
+    private String inCharges;
+
+    @ApiModelProperty(value = "Visible range for template")
+    private String visibleRange;
+
+    @ApiModelProperty(value = "Current user", hidden = true)
+    private String currentUser;
+
+    @ApiModelProperty(value = "Inlong tenant name", hidden = true)
+    private String tenant;
+
+    @ApiModelProperty(value = "weather is admin role.", hidden = true)
+    private Boolean isAdminRole;
+}
diff --git 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateRequest.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateRequest.java
new file mode 100644
index 0000000000..c994c70df5
--- /dev/null
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/TemplateRequest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.pojo.stream;
+
+import org.apache.inlong.manager.common.validation.SaveValidation;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+import java.util.List;
+
+/**
+ * Inlong template request.
+ */
+@Data
+@ApiModel("Inlong template request")
+public class TemplateRequest {
+
+    @ApiModelProperty(value = "Primary key")
+    private Integer id;
+
+    @ApiModelProperty(value = "Template name")
+    @NotBlank(groups = SaveValidation.class, message = "template name cannot 
be blank")
+    private String name;
+
+    @ApiModelProperty(value = "Name of responsible person, separated by 
commas")
+    private String inCharges;
+
+    @ApiModelProperty(value = "Visible range for template")
+    private String visibleRange;
+
+    @ApiModelProperty(value = "Field list")
+    private List<TemplateField> fieldList;
+
+    @ApiModelProperty(value = "Bind tenants")
+    private List<String> tenantList;
+
+    @ApiModelProperty(value = "Version number")
+    private Integer version;
+
+}
diff --git 
a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/stream/TemplateService.java
 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/stream/TemplateService.java
new file mode 100644
index 0000000000..4fecb6984f
--- /dev/null
+++ 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/stream/TemplateService.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.service.stream;
+
+import org.apache.inlong.manager.pojo.common.PageResult;
+import org.apache.inlong.manager.pojo.stream.TemplateInfo;
+import org.apache.inlong.manager.pojo.stream.TemplatePageRequest;
+import org.apache.inlong.manager.pojo.stream.TemplateRequest;
+
+/**
+ * Template service layer interface
+ */
+public interface TemplateService {
+
+    /**
+     * Save inlong template information.
+     *
+     * @param request Inlong template information.
+     * @param operator The name of operator.
+     * @return Id after successful save.
+     */
+    Integer save(TemplateRequest request, String operator);
+
+    /**
+     * Query whether the inlong template name exists
+     *
+     * @param templateName template name
+     * @return true: exists, false: does not exist
+     */
+    Boolean exist(String templateName);
+
+    /**
+     * Query the details of the specified inlong template
+     *
+     * @param templateName Inlong group id
+     * @return inlong template details
+     */
+    TemplateInfo get(String templateName, String operator);
+
+    /**
+     * Paging query inlong template info list
+     *
+     * @param request query request
+     * @return inlong template list
+     */
+    PageResult<TemplateInfo> list(TemplatePageRequest request);
+
+    Boolean update(TemplateRequest request, String operator);
+
+    /**
+     * Delete the specified inlong template.
+     *
+     * @param templateName template name
+     * @param operator operator
+     * @return whether succeed
+     */
+    Boolean delete(String templateName, String operator);
+
+    /**
+     * Delete the specified inlong template.
+     *
+     * @param templateId template id
+     * @param operator operator
+     * @return whether succeed
+     */
+    Boolean delete(Integer templateId, String operator);
+
+}
diff --git 
a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/stream/TemplateServiceImpl.java
 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/stream/TemplateServiceImpl.java
new file mode 100644
index 0000000000..f394730f37
--- /dev/null
+++ 
b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/stream/TemplateServiceImpl.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.service.stream;
+
+import org.apache.inlong.manager.common.consts.InlongConstants;
+import org.apache.inlong.manager.common.enums.ErrorCodeEnum;
+import org.apache.inlong.manager.common.enums.TemplateVisibleRange;
+import org.apache.inlong.manager.common.exceptions.BusinessException;
+import org.apache.inlong.manager.common.util.CommonBeanUtils;
+import org.apache.inlong.manager.common.util.Preconditions;
+import org.apache.inlong.manager.dao.entity.TemplateEntity;
+import org.apache.inlong.manager.dao.entity.TemplateFieldEntity;
+import org.apache.inlong.manager.dao.mapper.TemplateEntityMapper;
+import org.apache.inlong.manager.dao.mapper.TemplateFieldEntityMapper;
+import org.apache.inlong.manager.pojo.common.PageResult;
+import org.apache.inlong.manager.pojo.stream.TemplateField;
+import org.apache.inlong.manager.pojo.stream.TemplateInfo;
+import org.apache.inlong.manager.pojo.stream.TemplatePageRequest;
+import org.apache.inlong.manager.pojo.stream.TemplateRequest;
+import org.apache.inlong.manager.pojo.user.LoginUserUtils;
+
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Inlong template service layer implementation
+ */
+@Service
+public class TemplateServiceImpl implements TemplateService {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(TemplateServiceImpl.class);
+
+    @Autowired
+    private TemplateEntityMapper templateEntityMapper;
+    @Autowired
+    private TemplateFieldEntityMapper templateFieldEntityMapper;
+
+    @Transactional(rollbackFor = Throwable.class)
+    @Override
+    public Integer save(TemplateRequest request, String operator) {
+        LOGGER.debug("begin to save template info={}", request);
+        Preconditions.expectNotNull(request, "inlong template info is empty");
+        String templateName = request.getName();
+        TemplateEntity existEntity = 
templateEntityMapper.selectByName(templateName);
+        if (existEntity != null) {
+            LOGGER.error("inlong template name [{}] has already exists", 
templateName);
+            throw new BusinessException(ErrorCodeEnum.TEMPLATE_NAME_DUPLICATE);
+        }
+        TemplateEntity templateEntity = 
CommonBeanUtils.copyProperties(request, TemplateEntity::new);
+        templateEntity.setCreator(operator);
+        templateEntity.setModifier(operator);
+
+        templateEntityMapper.insert(templateEntity);
+        request.setId(templateEntity.getId());
+        saveField(request);
+
+        LOGGER.info("success to save inlong stream info for template name={}", 
templateName);
+        return templateEntity.getId();
+    }
+
+    @Override
+    public Boolean exist(String templateName) {
+        Preconditions.expectNotBlank(templateName, 
ErrorCodeEnum.TEMPLATE_INFO_INCORRECT);
+        TemplateEntity templateEntity = 
templateEntityMapper.selectByName(templateName);
+        return templateEntity != null;
+    }
+
+    @Override
+    public TemplateInfo get(String templateName, String operator) {
+        LOGGER.debug("begin to get inlong template by template name={}", 
templateName);
+        Preconditions.expectNotBlank(templateName, 
ErrorCodeEnum.TEMPLATE_INFO_INCORRECT);
+
+        TemplateEntity templateEntity = 
templateEntityMapper.selectByName(templateName);
+        if (templateEntity == null) {
+            LOGGER.error("inlong template not found by template name={}", 
templateName);
+            throw new BusinessException(ErrorCodeEnum.TEMPLATE_INFO_INCORRECT);
+        }
+
+        TemplateInfo templateInfo = 
CommonBeanUtils.copyProperties(templateEntity, TemplateInfo::new);
+        List<TemplateField> templateFields = 
getTemplateFields(templateEntity.getId());
+        templateInfo.setFieldList(templateFields);
+        return templateInfo;
+    }
+
+    private void checkVis(TemplateEntity templateEntity, List<String> 
tenantList, String operator) {
+        if (Objects.equals(templateEntity.getVisibleRange(), 
TemplateVisibleRange.IN_CHARGE.name())
+                && !templateEntity.getInCharges().contains(operator)) {
+            throw new BusinessException("current user is not in charge");
+        }
+        if (Objects.equals(templateEntity.getVisibleRange(), 
TemplateVisibleRange.TENANT.name())
+                && 
!tenantList.contains(LoginUserUtils.getLoginUser().getTenant())) {
+            throw new BusinessException("current user is not in tenant");
+        }
+    }
+
+    @Override
+    public PageResult<TemplateInfo> list(TemplatePageRequest request) {
+        PageHelper.startPage(request.getPageNum(), request.getPageSize());
+        Page<TemplateEntity> entityPage = (Page<TemplateEntity>) 
templateEntityMapper.selectByCondition(request);
+        PageResult<TemplateInfo> pageResult = PageResult.fromPage(entityPage)
+                .map(entity -> {
+                    TemplateInfo response = 
CommonBeanUtils.copyProperties(entity, TemplateInfo::new);
+                    return response;
+                });
+        LOGGER.debug("success to list template page, result size {}", 
pageResult.getList().size());
+        return pageResult;
+    }
+
+    private List<TemplateField> getTemplateFields(Integer templateId) {
+        List<TemplateFieldEntity> fieldEntityList = 
templateFieldEntityMapper.selectByTemplateId(templateId);
+        if (CollectionUtils.isEmpty(fieldEntityList)) {
+            return Collections.emptyList();
+        }
+        return CommonBeanUtils.copyListProperties(fieldEntityList, 
TemplateField::new);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Throwable.class)
+    public Boolean update(TemplateRequest request, String operator) {
+        LOGGER.debug("begin to update inlong template, request={}", request);
+
+        String templateName = request.getName();
+        TemplateEntity templateEntity = 
templateEntityMapper.selectByName(templateName);
+        if (templateEntity == null) {
+            LOGGER.error("inlong template not found by template name={}", 
templateName);
+            throw new BusinessException(ErrorCodeEnum.TEMPLATE_INFO_INCORRECT);
+        }
+
+        if (templateEntity.getInCharges().contains(operator)) {
+            throw new 
BusinessException(ErrorCodeEnum.TEMPLATE_PERMISSION_DENIED,
+                    String.format("user [%s] has no update privilege for the 
inlong temlate", operator));
+        }
+
+        String errMsg = String.format("template has already updated with 
template name=%s, curVersion=%s",
+                templateEntity.getName(), request.getVersion());
+        if (!Objects.equals(templateEntity.getVersion(), 
request.getVersion())) {
+            LOGGER.error(errMsg);
+            throw new BusinessException(ErrorCodeEnum.CONFIG_EXPIRED);
+        }
+
+        CommonBeanUtils.copyProperties(request, templateEntity, true);
+        templateEntity.setModifier(operator);
+        int rowCount = 
templateEntityMapper.updateByIdSelective(templateEntity);
+        if (rowCount != InlongConstants.AFFECTED_ONE_ROW) {
+            LOGGER.error(errMsg);
+            throw new BusinessException(ErrorCodeEnum.CONFIG_EXPIRED);
+        }
+        // update template fields
+        updateField(request);
+
+        LOGGER.info("success to update inlong template for template name={}", 
templateName);
+        return true;
+
+    }
+
+    @Override
+    @Transactional(rollbackFor = Throwable.class)
+    public Boolean delete(Integer id, String operator) {
+        LOGGER.debug("begin to delete inlong template, Id={}", id);
+
+        TemplateEntity entity = templateEntityMapper.selectByPrimaryKey(id);
+        if (entity == null) {
+            LOGGER.error("inlong template not found by template id={}", id);
+            throw new BusinessException(ErrorCodeEnum.TEMPLATE_NOT_FOUND);
+        }
+
+        if (entity.getInCharges().contains(operator)) {
+            throw new 
BusinessException(ErrorCodeEnum.TEMPLATE_PERMISSION_DENIED,
+                    String.format("user [%s] has no delete privilege for the 
inlong template", operator));
+        }
+
+        entity.setIsDeleted(entity.getId());
+        entity.setModifier(operator);
+        int rowCount = templateEntityMapper.updateByIdSelective(entity);
+        if (rowCount != InlongConstants.AFFECTED_ONE_ROW) {
+            LOGGER.error("template has already updated with template id={}, 
curVersion={}",
+                    id, entity.getVersion());
+            throw new BusinessException(ErrorCodeEnum.CONFIG_EXPIRED);
+        }
+        // Logically delete the associated field table
+        LOGGER.debug("begin to delete inlong template field, templateId={}", 
id);
+        templateFieldEntityMapper.logicDeleteAllByTemplateId(id);
+
+        LOGGER.info("success to delete inlong template, fields for 
templateId={}", id);
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Throwable.class)
+    public Boolean delete(String templateName, String operator) {
+        LOGGER.debug("begin to delete inlong template, template name={}", 
templateName);
+
+        TemplateEntity entity = 
templateEntityMapper.selectByName(templateName);
+        if (entity == null) {
+            LOGGER.error("inlong template not found by template name={}", 
templateName);
+            throw new BusinessException(ErrorCodeEnum.TEMPLATE_NOT_FOUND);
+        }
+
+        if (entity.getInCharges().contains(operator)) {
+            throw new 
BusinessException(ErrorCodeEnum.TEMPLATE_PERMISSION_DENIED,
+                    String.format("user [%s] has no delete privilege for the 
inlong template", operator));
+        }
+
+        entity.setIsDeleted(entity.getId());
+        entity.setModifier(operator);
+        int rowCount = templateEntityMapper.updateByIdSelective(entity);
+        if (rowCount != InlongConstants.AFFECTED_ONE_ROW) {
+            LOGGER.error("template has already updated with template name={}, 
curVersion={}",
+                    templateName, entity.getVersion());
+            throw new BusinessException(ErrorCodeEnum.CONFIG_EXPIRED);
+        }
+        // Logically delete the associated field table
+        LOGGER.debug("begin to delete inlong template field, templateId={}", 
templateName);
+        templateFieldEntityMapper.logicDeleteAllByTemplateId(entity.getId());
+
+        LOGGER.info("success to delete inlong template, fields for 
templateName={}", templateName);
+        return true;
+    }
+
+    @Transactional(rollbackFor = Throwable.class)
+    public void saveField(TemplateRequest request) {
+        List<TemplateField> fieldList = request.getFieldList();
+        LOGGER.debug("begin to save template fields={}", fieldList);
+        if (CollectionUtils.isEmpty(fieldList)) {
+            return;
+        }
+
+        int size = fieldList.size();
+        List<TemplateFieldEntity> entityList = new ArrayList<>(size);
+        Integer templateId = request.getId();
+        for (TemplateField fieldInfo : fieldList) {
+            TemplateFieldEntity fieldEntity = 
CommonBeanUtils.copyProperties(fieldInfo, TemplateFieldEntity::new);
+            if (StringUtils.isEmpty(fieldEntity.getFieldComment())) {
+                fieldEntity.setFieldComment(fieldEntity.getFieldName());
+            }
+            fieldEntity.setTemplateId(templateId);
+            fieldEntity.setIsDeleted(InlongConstants.UN_DELETED);
+            entityList.add(fieldEntity);
+        }
+
+        templateFieldEntityMapper.insertAll(entityList);
+        LOGGER.debug("success to save sink fields");
+    }
+
+    @Transactional(rollbackFor = Throwable.class)
+    public void updateField(TemplateRequest request) {
+        Integer templateId = request.getId();
+        List<TemplateField> fieldRequestList = request.getFieldList();
+        if (CollectionUtils.isEmpty(fieldRequestList)) {
+            return;
+        }
+
+        // First physically delete the existing fields
+        templateFieldEntityMapper.deleteAllByTemplateId(templateId);
+        // Then batch save the sink fields
+        this.saveField(request);
+        LOGGER.info("success to update template field");
+    }
+
+}
diff --git 
a/inlong-manager/manager-test/src/main/resources/h2/apache_inlong_manager.sql 
b/inlong-manager/manager-test/src/main/resources/h2/apache_inlong_manager.sql
index 79d19a57e1..9739482638 100644
--- 
a/inlong-manager/manager-test/src/main/resources/h2/apache_inlong_manager.sql
+++ 
b/inlong-manager/manager-test/src/main/resources/h2/apache_inlong_manager.sql
@@ -901,6 +901,47 @@ CREATE TABLE IF NOT EXISTS `cluster_config`
     UNIQUE KEY `unique_clustert_config_sink_id` (`cluster_tag`, `is_deleted`)
 );
 
+-- ----------------------------
+-- Table structure for template
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `template`
+(
+    `id`                  int(11)       NOT NULL AUTO_INCREMENT COMMENT 
'Incremental primary key',
+    `name`                varchar(128)  NOT NULL COMMENT 'Inlong cluster tag',
+    `in_charges`          varchar(512)  NOT NULL COMMENT 'Name of responsible 
person, separated by commas',
+    `visible_range`       text          NOT NULL COMMENT 'Visible range of 
template',
+    `creator`             varchar(128)  DEFAULT NULL COMMENT 'Creator',
+    `modifier`            varchar(128)  DEFAULT NULL COMMENT 'Modifier name',
+    `create_time`         datetime      NOT NULL DEFAULT CURRENT_TIMESTAMP 
COMMENT 'Create time',
+    `modify_time`         datetime      NOT NULL DEFAULT CURRENT_TIMESTAMP ON 
UPDATE CURRENT_TIMESTAMP COMMENT 'Modify time',
+    `is_deleted`          int(11)       DEFAULT '0' COMMENT 'Whether to 
delete, 0 is not deleted, if greater than 0, delete',
+    `version`             int(11)       NOT NULL DEFAULT '1' COMMENT 'Version 
number, which will be incremented by 1 after modification',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `unique_template_name` (`name`, `is_deleted`)
+);
+
+-- ----------------------------
+-- Table structure for template field
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `template_field`
+(
+    `id`                  int(11)      NOT NULL AUTO_INCREMENT COMMENT 
'Incremental primary key',
+    `template_id`         int(11)      NOT NULL COMMENT 'Owning template id',
+    `is_predefined_field` tinyint(1)   DEFAULT '0' COMMENT 'Whether it is a 
predefined field, 0: no, 1: yes',
+    `field_name`          varchar(120) NOT NULL COMMENT 'field name',
+    `field_value`         varchar(128) DEFAULT NULL COMMENT 'Field value, 
required if it is a predefined field',
+    `pre_expression`      varchar(256) DEFAULT NULL COMMENT 'Pre-defined field 
value expression',
+    `field_type`          varchar(20)  NOT NULL COMMENT 'field type',
+    `field_comment`       varchar(50)  DEFAULT NULL COMMENT 'Field 
description',
+    `is_meta_field`       smallint(3)  DEFAULT '0' COMMENT 'Is this field a 
meta field? 0: no, 1: yes',
+    `meta_field_name`     varchar(120) DEFAULT NULL COMMENT 'Meta field name',
+    `field_format`        text         DEFAULT NULL COMMENT 'Field format, 
including: MICROSECONDS, MILLISECONDS, SECONDS, custom such as yyyy-MM-dd 
HH:mm:ss, and serialize format of complex type or decimal precision, etc.',
+    `rank_num`            smallint(6)  DEFAULT '0' COMMENT 'Field order 
(front-end display field order)',
+    `is_deleted`          int(11)      DEFAULT '0' COMMENT 'Whether to delete, 
0: not deleted, > 0: deleted',
+    PRIMARY KEY (`id`),
+    INDEX `template_field_index` (`template_id`)
+);
+
 -- ----------------------------
 
 SET FOREIGN_KEY_CHECKS = 1;
diff --git a/inlong-manager/manager-web/sql/apache_inlong_manager.sql 
b/inlong-manager/manager-web/sql/apache_inlong_manager.sql
index 849ffa6d4d..3184f880e8 100644
--- a/inlong-manager/manager-web/sql/apache_inlong_manager.sql
+++ b/inlong-manager/manager-web/sql/apache_inlong_manager.sql
@@ -951,6 +951,50 @@ CREATE TABLE IF NOT EXISTS `cluster_config`
     UNIQUE KEY `unique_clustert_config_sink_id` (`cluster_tag`, `is_deleted`)
 ) ENGINE = InnoDB
     DEFAULT CHARSET = utf8mb4 COMMENT = 'cluster_config';
+
+-- ----------------------------
+-- Table structure for template
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `template`
+(
+    `id`                  int(11)       NOT NULL AUTO_INCREMENT COMMENT 
'Incremental primary key',
+    `name`                varchar(128)  NOT NULL COMMENT 'Inlong cluster tag',
+    `in_charges`          varchar(512)  NOT NULL COMMENT 'Name of responsible 
person, separated by commas',
+    `visible_range`       text          NOT NULL COMMENT 'Visible range of 
template',
+    `creator`             varchar(128)  DEFAULT NULL COMMENT 'Creator',
+    `modifier`            varchar(128)  DEFAULT NULL COMMENT 'Modifier name',
+    `create_time`         datetime      NOT NULL DEFAULT CURRENT_TIMESTAMP 
COMMENT 'Create time',
+    `modify_time`         datetime      NOT NULL DEFAULT CURRENT_TIMESTAMP ON 
UPDATE CURRENT_TIMESTAMP COMMENT 'Modify time',
+    `is_deleted`          int(11)       DEFAULT '0' COMMENT 'Whether to 
delete, 0 is not deleted, if greater than 0, delete',
+    `version`             int(11)       NOT NULL DEFAULT '1' COMMENT 'Version 
number, which will be incremented by 1 after modification',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `unique_template_name` (`name`, `is_deleted`)
+    ) ENGINE = InnoDB
+    DEFAULT CHARSET = utf8mb4 COMMENT = 'template';
+
+-- ----------------------------
+-- Table structure for template field
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `template_field`
+(
+    `id`                  int(11)      NOT NULL AUTO_INCREMENT COMMENT 
'Incremental primary key',
+    `template_id`         int(11)      NOT NULL COMMENT 'Owning template id',
+    `is_predefined_field` tinyint(1)   DEFAULT '0' COMMENT 'Whether it is a 
predefined field, 0: no, 1: yes',
+    `field_name`          varchar(120) NOT NULL COMMENT 'field name',
+    `field_value`         varchar(128) DEFAULT NULL COMMENT 'Field value, 
required if it is a predefined field',
+    `pre_expression`      varchar(256) DEFAULT NULL COMMENT 'Pre-defined field 
value expression',
+    `field_type`          varchar(20)  NOT NULL COMMENT 'field type',
+    `field_comment`       varchar(50)  DEFAULT NULL COMMENT 'Field 
description',
+    `is_meta_field`       smallint(3)  DEFAULT '0' COMMENT 'Is this field a 
meta field? 0: no, 1: yes',
+    `meta_field_name`     varchar(120) DEFAULT NULL COMMENT 'Meta field name',
+    `field_format`        text         DEFAULT NULL COMMENT 'Field format, 
including: MICROSECONDS, MILLISECONDS, SECONDS, custom such as yyyy-MM-dd 
HH:mm:ss, and serialize format of complex type or decimal precision, etc.',
+    `rank_num`            smallint(6)  DEFAULT '0' COMMENT 'Field order 
(front-end display field order)',
+    `is_deleted`          int(11)      DEFAULT '0' COMMENT 'Whether to delete, 
0: not deleted, > 0: deleted',
+    PRIMARY KEY (`id`),
+    INDEX `template_field_index` (`template_id`)
+) ENGINE = InnoDB
+    DEFAULT CHARSET = utf8mb4 COMMENT ='Template field table';
+
 -- ----------------------------
 
 SET FOREIGN_KEY_CHECKS = 1;
diff --git a/inlong-manager/manager-web/sql/changes-1.13.0.sql 
b/inlong-manager/manager-web/sql/changes-1.13.0.sql
index 7013c2990f..f671e57c86 100644
--- a/inlong-manager/manager-web/sql/changes-1.13.0.sql
+++ b/inlong-manager/manager-web/sql/changes-1.13.0.sql
@@ -26,3 +26,46 @@ USE `apache_inlong_manager`;
 ALTER TABLE `inlong_cluster_node` ADD COLUMN  `username` varchar(256) DEFAULT 
NULL COMMENT 'username for ssh';
 ALTER TABLE `inlong_cluster_node` ADD COLUMN  `password` varchar(256) DEFAULT 
NULL COMMENT 'password for ssh';
 ALTER TABLE `inlong_cluster_node` ADD COLUMN  `ssh_port` int(11) DEFAULT NULL 
COMMENT 'ssh port';
+
+-- ----------------------------
+-- Table structure for template
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `template`
+(
+    `id`                  int(11)       NOT NULL AUTO_INCREMENT COMMENT 
'Incremental primary key',
+    `name`                varchar(128)  NOT NULL COMMENT 'Inlong cluster tag',
+    `in_charges`          varchar(512)  NOT NULL COMMENT 'Name of responsible 
person, separated by commas',
+    `visible_range`       text          NOT NULL COMMENT 'Visible range of 
template',
+    `creator`             varchar(128)  DEFAULT NULL COMMENT 'Creator',
+    `modifier`            varchar(128)  DEFAULT NULL COMMENT 'Modifier name',
+    `create_time`         datetime      NOT NULL DEFAULT CURRENT_TIMESTAMP 
COMMENT 'Create time',
+    `modify_time`         datetime      NOT NULL DEFAULT CURRENT_TIMESTAMP ON 
UPDATE CURRENT_TIMESTAMP COMMENT 'Modify time',
+    `is_deleted`          int(11)       DEFAULT '0' COMMENT 'Whether to 
delete, 0 is not deleted, if greater than 0, delete',
+    `version`             int(11)       NOT NULL DEFAULT '1' COMMENT 'Version 
number, which will be incremented by 1 after modification',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `unique_template_name` (`name`, `is_deleted`)
+) ENGINE = InnoDB
+    DEFAULT CHARSET = utf8mb4 COMMENT = 'template';
+
+-- ----------------------------
+-- Table structure for template field
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `template_field`
+(
+    `id`                  int(11)      NOT NULL AUTO_INCREMENT COMMENT 
'Incremental primary key',
+    `template_id`         int(11)      NOT NULL COMMENT 'Owning template id',
+    `is_predefined_field` tinyint(1)   DEFAULT '0' COMMENT 'Whether it is a 
predefined field, 0: no, 1: yes',
+    `field_name`          varchar(120) NOT NULL COMMENT 'field name',
+    `field_value`         varchar(128) DEFAULT NULL COMMENT 'Field value, 
required if it is a predefined field',
+    `pre_expression`      varchar(256) DEFAULT NULL COMMENT 'Pre-defined field 
value expression',
+    `field_type`          varchar(20)  NOT NULL COMMENT 'field type',
+    `field_comment`       varchar(50)  DEFAULT NULL COMMENT 'Field 
description',
+    `is_meta_field`       smallint(3)  DEFAULT '0' COMMENT 'Is this field a 
meta field? 0: no, 1: yes',
+    `meta_field_name`     varchar(120) DEFAULT NULL COMMENT 'Meta field name',
+    `field_format`        text         DEFAULT NULL COMMENT 'Field format, 
including: MICROSECONDS, MILLISECONDS, SECONDS, custom such as yyyy-MM-dd 
HH:mm:ss, and serialize format of complex type or decimal precision, etc.',
+    `rank_num`            smallint(6)  DEFAULT '0' COMMENT 'Field order 
(front-end display field order)',
+    `is_deleted`          int(11)      DEFAULT '0' COMMENT 'Whether to delete, 
0: not deleted, > 0: deleted',
+    PRIMARY KEY (`id`),
+    INDEX `template_field_index` (`template_id`)
+) ENGINE = InnoDB
+    DEFAULT CHARSET = utf8mb4 COMMENT ='Template field table';

Reply via email to