diff --git a/src/main/java/com/supervision/service/QueryTemplateProcessor.java b/src/main/java/com/supervision/service/QueryTemplateProcessor.java new file mode 100644 index 0000000..68f10dc --- /dev/null +++ b/src/main/java/com/supervision/service/QueryTemplateProcessor.java @@ -0,0 +1,24 @@ +package com.supervision.service; + +import java.util.Map; + +/** + * 通过问询模板查询数据,并返回结果模板 + */ +public interface QueryTemplateProcessor { + + /** + * 根据模板id查询结果 + * @param templateId 模板id + * @return 回答结果 + */ + String query(String templateId); + + /** + * 根据模板id和输入参数查询结果 + * @param templateId 模板id + * @param input 入参 + * @return 回答结果 + */ + String query(String templateId, Map input); +} diff --git a/src/main/java/com/supervision/service/TalkService.java b/src/main/java/com/supervision/service/TalkService.java new file mode 100644 index 0000000..b908e2d --- /dev/null +++ b/src/main/java/com/supervision/service/TalkService.java @@ -0,0 +1,15 @@ +package com.supervision.service; + +/** + * 对话服务 + * + */ +public interface TalkService { + + /** + * 回答问题 + * @param questionId 问题id + * @return 回答内容 + */ + String answer(String questionId); +} diff --git a/src/main/java/com/supervision/service/impl/QueryTemplateProcessorImpl.java b/src/main/java/com/supervision/service/impl/QueryTemplateProcessorImpl.java new file mode 100644 index 0000000..cd897c7 --- /dev/null +++ b/src/main/java/com/supervision/service/impl/QueryTemplateProcessorImpl.java @@ -0,0 +1,118 @@ +package com.supervision.service.impl; + +import cn.hutool.core.lang.Assert; +import com.supervision.domain.IrKnowledge; +import com.supervision.domain.IrSessionParam; +import com.supervision.domain.IrSqlParam; +import com.supervision.service.IrKnowledgeService; +import com.supervision.service.IrSessionParamService; +import com.supervision.service.IrSqlParamService; +import com.supervision.service.QueryTemplateProcessor; +import com.supervision.util.ParamTypeConverter; +import com.supervision.util.mybatis.RowSqlMapper; +import freemarker.cache.StringTemplateLoader; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.swing.tree.RowMapper; +import java.io.IOException; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class QueryTemplateProcessorImpl implements QueryTemplateProcessor { + + private final IrKnowledgeService knowledgeService; + + private final IrSqlParamService sqlParamService; + + private final IrSessionParamService sessionParamService; + + private final freemarker.template.Configuration databaseFreemarkerConfiguration; + + private final RowSqlMapper rowSqlMapper; + @Override + public String query(String templateId) { + + Assert.notEmpty(templateId, "模板ID不能为空"); + + IrKnowledge knowledge = knowledgeService.getById(templateId); + Assert.notNull(knowledge, "知识不存在!"); + Assert.notEmpty(knowledge.getSqlTemplate(), "模板内容不能为空"); + Assert.notEmpty(knowledge.getResultTemplate(), "结果模板不能为空"); + // 查询必填的参数 + List paramsList = sqlParamService.lambdaQuery().eq(IrSqlParam::getKnowledgeId, templateId).eq(IrSqlParam::getParamRequire, 1).list(); + + // 校验必填参数 + List sessionParams = sessionParamService.lambdaQuery().eq(IrSessionParam::getSessionId, templateId).list(); + Set sessionParamsNames = sessionParams.stream().map(IrSessionParam::getParamName).collect(Collectors.toSet()); + paramsList.forEach(param -> Assert.isTrue(sessionParamsNames.contains(param.getId()))); + + + // 获取执行sql + ParamTypeConverter converter = ParamTypeConverter.getInstance(); + Map params = sessionParams.stream().collect(Collectors.toMap(IrSessionParam::getParamName, v->converter.convert(v.getParamValue(),v.getParamType()), (v1, v2) -> v1)); + String query = query(templateId, params); + + List> maps = rowSqlMapper.selectList(knowledge.getSqlTemplate(), params); + + + // 组装返回结果 + + //templateProcess(maps, knowledge.getResultTemplate()) + return null; + } + + @Override + public String query(String templateId, Map input) { + + Template template = null; + try { + template = databaseFreemarkerConfiguration.getTemplate(templateId); + } catch (IOException e) { + log.error("加载模板失败:模板id:{}",templateId,e); + return null; + } + //databaseFreemarkerConfiguration.gett + StringWriter writer = new StringWriter(); + try { + template.process(input, writer); + } catch (TemplateException | IOException e) { + log.error("模板执行失败",e); + return null; + }finally { + try { + writer.close(); + } catch (IOException e) { + log.error("关闭流失败", e); + } + } + return writer.toString(); + } + + private String templateProcess(String templateId,String context, Map input) throws IOException, TemplateException { + Configuration cfg = new Configuration(Configuration.VERSION_2_3_30); + + StringTemplateLoader stringLoader = new StringTemplateLoader(); + stringLoader.putTemplate(templateId, context); + cfg.setTemplateLoader(stringLoader); + Template template = cfg.getTemplate(templateId); + StringWriter output = new StringWriter(); + template.process(input, output); + + return output.toString(); + } + + + +} diff --git a/src/main/java/com/supervision/util/ParamTypeConverter.java b/src/main/java/com/supervision/util/ParamTypeConverter.java new file mode 100644 index 0000000..b781430 --- /dev/null +++ b/src/main/java/com/supervision/util/ParamTypeConverter.java @@ -0,0 +1,135 @@ +package com.supervision.util; + +import cn.hutool.core.convert.ConverterRegistry; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.lang.Opt; +import cn.hutool.core.map.SafeConcurrentHashMap; + +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.time.*; +import java.time.temporal.TemporalAccessor; +import java.util.*; +import java.util.concurrent.atomic.*; + +public class ParamTypeConverter { + + private Map typeMap; + + private ParamTypeConverter(){ + defaultConverter(); + } + public Object convert(String paramType, Object paramValue) { + if (Objects.isNull(paramValue)) { + return null; + } + if (null == typeMap.get(paramType)){ + return null; + } + + return ConverterRegistry.getInstance().convert(typeMap.get(paramType), paramValue); + } + + + private static class SingletonHolder { + /** + * 静态初始化器,由JVM来保证线程安全 + */ + private static final ParamTypeConverter INSTANCE = new ParamTypeConverter(); + } + + public static ParamTypeConverter getInstance() { + return ParamTypeConverter.SingletonHolder.INSTANCE; + } + + private void defaultConverter() { + typeMap = new SafeConcurrentHashMap<>(); + + // 原始类型转换器 + typeMap.put("int",int.class); + typeMap.put("long", long.class); + typeMap.put("byte", byte.class); + typeMap.put("short", short.class); + typeMap.put("float", float.class); + typeMap.put("double", double.class); + typeMap.put("char", char.class); + typeMap.put("boolean", boolean.class); + + // 包装类转换器 + typeMap.put("Number", Number.class); + typeMap.put("Integer", Integer.class); + typeMap.put("AtomicInteger", AtomicInteger.class); + typeMap.put("Long", Long.class); + typeMap.put("LongAdder", LongAdder.class); + typeMap.put("AtomicLong", AtomicLong.class); + typeMap.put("Byte", Byte.class); + typeMap.put("Short", Short.class); + typeMap.put("Float", Float.class); + typeMap.put("Double", Double.class); + typeMap.put("DoubleAdder", DoubleAdder.class); + typeMap.put("Character", Character.class); + typeMap.put("Boolean", Boolean.class); + typeMap.put("AtomicBoolean", AtomicBoolean.class); + typeMap.put("BigDecimal", BigDecimal.class); + typeMap.put("BigInteger", BigInteger.class); + typeMap.put("CharSequence", CharSequence.class); + typeMap.put("String", String.class); + + // URI and URL + typeMap.put("URI", URI.class); + typeMap.put("URL", URL.class); + + // 日期时间 + typeMap.put("Calendar", Calendar.class); + typeMap.put("java.util.Date", java.util.Date.class); + typeMap.put("DateTime", DateTime.class); + typeMap.put("java.sql.Date", java.sql.Date.class); + typeMap.put("java.sql.Time", java.sql.Time.class); + typeMap.put("java.sql.Timestamp", java.sql.Timestamp.class); + + // 日期时间 JDK8+ + typeMap.put("TemporalAccessor", TemporalAccessor.class); + typeMap.put("Instant", Instant.class); + typeMap.put("LocalDateTime", LocalDateTime.class); + typeMap.put("LocalDate", LocalDate.class); + typeMap.put("LocalTime", LocalTime.class); + typeMap.put("ZonedDateTime", ZonedDateTime.class); + typeMap.put("OffsetDateTime", OffsetDateTime.class); + typeMap.put("OffsetTime", OffsetTime.class); + typeMap.put("DayOfWeek", DayOfWeek.class); + typeMap.put("Month", Month.class); + typeMap.put("MonthDay", MonthDay.class); + typeMap.put("Period", Period.class); + typeMap.put("Duration", Duration.class); + + // Reference + typeMap.put("WeakReference", WeakReference.class); + typeMap.put("SoftReference", SoftReference.class); + typeMap.put("AtomicReference", AtomicReference.class); + + // AtomicXXXArray + typeMap.put("AtomicIntegerArray", AtomicIntegerArray.class); + typeMap.put("AtomicLongArray", AtomicLongArray.class); + + // 其它类型 + typeMap.put("Class", Class.class); + typeMap.put("TimeZone", TimeZone.class); + typeMap.put("Locale", Locale.class); + typeMap.put("Charset", Charset.class); + typeMap.put("Path", Path.class); + typeMap.put("Currency", Currency.class); + typeMap.put("UUID", UUID.class); + typeMap.put("StackTraceElement", StackTraceElement.class); + typeMap.put("Optional", Optional.class); + typeMap.put("Opt", Opt.class); + + } + +} diff --git a/src/test/java/com/supervision/AskApplicationTests.java b/src/test/java/com/supervision/AskApplicationTests.java index d703d94..dcca2d7 100644 --- a/src/test/java/com/supervision/AskApplicationTests.java +++ b/src/test/java/com/supervision/AskApplicationTests.java @@ -2,6 +2,7 @@ package com.supervision; import com.supervision.service.IrKnowledgeService; import com.supervision.util.mybatis.RowSqlMapper; +import freemarker.cache.StringTemplateLoader; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; @@ -61,5 +62,35 @@ class AskApplicationTests { } + @Test + void stringTemplateLoaderTest() throws IOException, TemplateException { + Configuration cfg = new Configuration(Configuration.VERSION_2_3_30); + + // 创建一个 StringTemplateLoader 对象 + StringTemplateLoader stringLoader = new StringTemplateLoader(); + + // 添加模板到 StringTemplateLoader 中 + String templateContent = "Hello, ${user}!"; + stringLoader.putTemplate("myTemplate", templateContent); + + // 将 StringTemplateLoader 添加到 Configuration 中 + cfg.setTemplateLoader(stringLoader); + + // 获取模板 + Template template = cfg.getTemplate("myTemplate"); + + // 创建模板数据模型 + Map data = new HashMap<>(); + data.put("user", "John"); + + // 渲染模板 + StringWriter output = new StringWriter(); + template.process(data, output); + + // 打印输出结果 + System.out.println(output.toString()); + } + + }