平台配置日志输出和推送到APM与LogStash

场景描述

目前设计器镜像启动后日志文件为out.log,是启动脚本中定向输出了(>>)out.log文件。实际项目可能:

  • 日志输出到特定目录的特定文件名中
  • 指定以日志保留策略(单个文件大小和文件保留个数)
  • 日志输出到APM工具中(如skywalking)
  • 日志推送到LogStash

日志自定义输出

不定向输出,采用自己配置的方式,与标准的SpringBoot工程配置日志一样。两种方式(都是Spring提供的方式):

方式一

bootstrap.yml 里面可以按profiles指定logback的配置文件,具体文件名和文件输入在logback里面进行配置,跟通用的logback配置一致. 例如:

logging:
  config: classpath:logback-pre.xml

方式二

resources的根目录,直接配置 logback-spring.xml, 启动会自动加载。

日志自定义场景

配置日志推送到LogStash

    <!--配置日志推送到LogStash-->
    <contextListener class="pro.shushi.pamirs.demo.core.config.DemoLogbackFiledConfig"/>
    <appender name="LogStash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>127.0.0.1:4560</destination>
        <!-- encoder必须配置,有多种可选 -->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
            <!--  SkyWalking插件, log加tid-->
            <provider class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.logstash.TraceIdJsonProvider" />
            <!--在生成的json中会加这些字段-->
            <customFields>
                {"app.name":"pamirs-demo", "app.type":"Microservice", "platform":"pamirs", "env":"dev"}
            </customFields>
            <timeZone>Asia/Shanghai</timeZone>
            <writeVersionAsInteger>true</writeVersionAsInteger>
            <providers>
                <pattern>
                    <pattern>
                        <!--动态的变量-->
                        {
                        "ip": "%{ip}",
                        "server.name": "%{server.name}",
                        "logger_name": "%logger"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

skywalking的日志rpc上传

    <!-- skywalking的日志rpc上传 -->
    <appender name="SkyWalkingLogs" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>

完整的代码示例

  • Logback自定义字段
package pro.shushi.pamirs.demo.core.config;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggerContextListener;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.spi.ContextAwareBase;
import ch.qos.logback.core.spi.LifeCycle;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 *  Logback自定义字段
 *
 * @author wx@shushi.pro
 * @date 2024/4/17
 */
public class DemoLogbackFiledConfig extends ContextAwareBase implements LoggerContextListener, LifeCycle {

    private boolean started = false;

    @Override
    public boolean isResetResistant() {
        return false;
    }

    @Override
    public void onStart(LoggerContext loggerContext) {
    }

    @Override
    public void onReset(LoggerContext loggerContext) {
    }

    @Override
    public void onStop(LoggerContext loggerContext) {
    }

    @Override
    public void onLevelChange(Logger logger, Level level) {
    }

    @Override
    public void start() {
        if (started) {
            return;
        }
        Context context = getContext();
        // 机器名称
        context.putProperty("server.name", getHostName());
        // 机器IP地址
        context.putProperty("ip", getHostAddress());
        started = true;
    }

    @Override
    public void stop() {
    }

    @Override
    public boolean isStarted() {
        return false;
    }

    private String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }

    private String getHostAddress() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }
}
  • logback-dev.xml完整内容
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 日志输出格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="%d |-%p [%tid] %class:%line - %m%n"/>

    <!-- 控制台日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>${CONSOLE_LOG_PATTERN}</pattern><!-- 此处设置输出格式 -->
            </layout>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

    <!-- 文件日志 -->
    <appender name="fileLogger"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>/Users/wangxian/logs/pamirs-demo.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/Users/wangxian/logs/pamirs-demo-%d-%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 日志文件的最多存储64MB -->
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
           <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>${CONSOLE_LOG_PATTERN}</pattern><!-- 此处设置输出格式 -->
            </layout>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

    <!--配置日志推送到LogStash-->
    <contextListener class="pro.shushi.pamirs.demo.core.config.DemoLogbackFiledConfig"/>
    <appender name="LogStash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>127.0.0.1:4560</destination>
        <!-- encoder必须配置,有多种可选 -->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
            <!--  SkyWalking插件, log加tid-->
            <provider class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.logstash.TraceIdJsonProvider" />
            <!--在生成的json中会加这些字段-->
            <customFields>
                {"app.name":"pamirs-demo", "app.type":"Microservice", "platform":"pamirs", "env":"dev"}
            </customFields>
            <timeZone>Asia/Shanghai</timeZone>
            <writeVersionAsInteger>true</writeVersionAsInteger>
            <providers>
                <pattern>
                    <pattern>
                        <!--动态的变量-->
                        {
                        "ip": "%{ip}",
                        "server.name": "%{server.name}",
                        "logger_name": "%logger"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

    <!-- skywalking的日志rpc上传 -->
    <appender name="SkyWalkingLogs" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="LogStash"/>
        <appender-ref ref="SkyWalkingLogs"/>
    </root>

    <!-- Nacos的心跳检测日志级别设置 (会自动继承root 的appender) -->
    <logger name="com.alibaba" level="ERROR">
    </logger>
    <!-- xxl-job心跳检查日志级别 -->
    <logger name="com.xxl.job.core.thread" level="ERROR"/>
</configuration>
  • 分为debug、info、warn、error四种类型的日志信息,分别保存到此四个文件夹中,并按大小和日期进行归档
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->

<!-- 根节点<configuration>,包含下面三个属性:-->
<!-- scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。-->
<!-- scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。-->
<!-- debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。-->
<configuration>
   <contextName>dimples-logback</contextName>
   <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
   <property name="log.path" value="C:/springboot-log/logs" />

   <!-- 彩色日志 -->
   <!-- 彩色日志依赖的渲染类 -->
   <conversionRule conversionWord="clr"
      converterClass="org.springframework.boot.logging.logback.ColorConverter" />
   <conversionRule conversionWord="wex"
      converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
   <conversionRule conversionWord="wEx"
      converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
   <!-- 彩色日志格式 -->
   <property name="CONSOLE_LOG_PATTERN"
      value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
   <property name="log.colorPattern" value="%magenta(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %boldCyan([${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]) %yellow(%thread) %green(%logger) %msg%n"/>
   <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level [${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}] %thread %logger %msg%n"/>
   <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
   <!-- appender是configuration的子节点,是负责写日志的组件。 -->
   <!-- ConsoleAppender:把日志输出到控制台 -->
   <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
         <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
         <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
         <charset>UTF-8</charset>
      </encoder>
   </appender>

   <!-- 时间滚动输出 level为 DEBUG 日志 -->
   <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\debug/log_debug.log</file>
      <!--日志信息输出格式-->
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         <charset>UTF-8</charset> <!-- 设置字符集 -->
      </encoder>
      <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <!-- 日志归档 -->
         <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>15</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录debug级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>debug</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>

   <!-- 时间滚动输出 level为 INFO 日志 -->
   <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\info/log_info.log</file>
      <!--日志信息输出格式-->
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         <charset>UTF-8</charset>
      </encoder>
      <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <!-- 每天日志归档路径以及格式 -->
         <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>15</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录info级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>info</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>

   <!-- 时间滚动输出 level为 WARN 日志 -->
   <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\warn/log_warn.log</file>
      <!--日志信息输出格式-->
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         <charset>UTF-8</charset> <!-- 此处设置字符集 -->
      </encoder>
      <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>30</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录warn级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>warn</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>
   <!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
   <!--             2.如果日期没有发生变化,但是当前日志的文件大小超过1KB时,对当前日志进行分割 重命名-->
   <!-- 时间滚动输出 level为 ERROR 日志 -->
   <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\error/log_error.log</file>
      <!--日志信息输出格式-->
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         <charset>UTF-8</charset> <!-- 此处设置字符集 -->
      </encoder>
      <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>30</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录ERROR级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>ERROR</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>
   <!--开发环境:打印控制台-->
   <!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
   <!-- com.dimples.springboot.biz为业务逻辑根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
   <!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE  -->
   <springProfile name="dev">
      <logger name="com.dimples.springboot.biz" level="debug" />
   </springProfile>
   <!-- 控制台输出日志级别 -->
   <root level="info">
      <appender-ref ref="CONSOLE" />
      <appender-ref ref="DEBUG_FILE" />
      <appender-ref ref="INFO_FILE" />
      <appender-ref ref="WARN_FILE" />
      <appender-ref ref="ERROR_FILE" />
   </root>

   <!--生产环境:输出到文件-->
   <!--<springProfile name="pro">-->
   <!--<root level="info">-->
   <!--<appender-ref ref="CONSOLE" />-->
   <!--<appender-ref ref="DEBUG_FILE" />-->
   <!--<appender-ref ref="INFO_FILE" />-->
   <!--<appender-ref ref="ERROR_FILE" />-->
   <!--<appender-ref ref="WARN_FILE" />-->
   <!--</root>-->
   <!--</springProfile>-->
</configuration>

Oinone社区 作者:望闲原创文章,如若转载,请注明出处:https://doc.oinone.top/install/7370.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
望闲's avatar望闲数式管理员
Previous 2024年5月18日 pm3:14
Next 2024年5月18日 pm4:45

相关推荐

  • 项目中排除掉特定的Hook和扩展点

    总体介绍 在共库共Redis的情况下,某些场景存在需要过滤掉特定Hook和扩展点(extpoint)的情况。本文介绍排除掉的配置方法 1. Oinone如何排除特定的Hook 配置: pamirs: framework: hook: excludes: – 排除的扩展点列表 示例: pamirs: framework: hook: excludes: – pro.shushi.pamirs.timezone.hook.TimezoneHookBefore – pro.shushi.pamirs.timezone.hook.TimezoneHookAfter – pro.shushi.pamirs.timezone.hook.TimezoneSessionInitHook – pro.shushi.pamirs.translate.hook.TranslateAfterHook 2. Oinone如何排除特定的扩展点 配置 pamirs: framework: extpoint: excludes: – 排除的扩展点列表 示例: pamirs: framework: extpoint: excludes: – pro.shushi.pamirs.demo.core.extpoint.PetCatTypeExtPoint

    2024年5月13日
    1.6K00
  • Oinone请求调用链路

    Oinone请求调用链路 请求格式与简单流程 在Oinone中请求数据存储在请求体中,以GQL的方式进行表示,也就是GQL格式的请求。 当我们发送一个GQL格式的请求,后端会对GQL进行解析,确定想要执行的方法,并对这个方法执行过程中所用到的模型进行构建,最后返回响应。 请求 # 请求路径 pamirs/base http://127.0.0.1:8090/pamirs/base # 请求体内容 query{ petShopProxyBQuery{ sayHello(shop:{shopName:"cpc"}){ shopName } } } 解析 # 简单理解 query 操作类型 petShopProxyBQuery 模块名称 + Query sayHello 方法 fun sayHello() 可以传入参数,参数名为 shop shopName 需要得到的值 响应 # data中的内容 "data": { "petShopQuery": { "hello": { "shopName": "cpc" } } } 具体流程 Oinone是基于SpringBoot的,在Controller中处理请求 会接收所有以 /pamirs 开始的POST请求,/pamirs/后携带的是模块名 @RequestMapping( value = "/pamirs/{moduleName:^[a-zA-Z][a-zA-Z0-9_]+[a-zA-Z0-9]$}", method = RequestMethod.POST ) public String pamirsPost(@PathVariable("moduleName") String moduleName, @RequestBody PamirsClientRequestParam gql, HttpServletRequest request, HttpServletResponse response) { …….. } 整体脉络 第四步执行中有两大重要的步骤,一步是动态构建GQL,一步是执行请求。 动态构建GQL 请求执行

    2024年12月1日
    1.5K00
  • 框架之MessageHub(信息提示)

    框架之信息概述 后端除了可以返回错误信息以外,还可以返回调试、告警、成功、信息等级别的信息给前端。但是默认情况下前端只提示错误信息,可以通过前端的统一配置放开提示级别,有点类似后端的日志级别。 框架之MessageHub 在oinone平台中,我们怎么做到友好的错误提示呢?接下来介绍我们的MessageHub,它为自定义错误提示提供无限的可能。 何时使用 错误提示是用户体验中特别重要的组成部分,大部分的错误体现在整页级别,字段级别,按钮级别。友好的错误提示应该是怎么样的呢?我们假设他是这样的 与用户操作精密契合 当字段输入异常时,错误展示在错误框底部 按钮触发服务时异常,错误展示在按钮底部 区分不同的类型 错误 成功 警告 提示 调试 简洁易懂的错误信息 不同信息类型的举例 package pro.shushi.pamirs.demo.core.action; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.PetCatItem; import pro.shushi.pamirs.demo.api.model.PetType; import pro.shushi.pamirs.meta.annotation.Action; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.api.dto.common.Message; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum; import pro.shushi.pamirs.meta.enmu.InformationLevelEnum; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; @Model.model(PetType.MODEL_MODEL) @Component public class PetTypeAction { @Action(displayName = "消息",bindingType = ViewTypeEnum.TABLE,contextType = ActionContextTypeEnum.CONTEXT_FREE) public PetType message(PetType data){ PamirsSession.getMessageHub().info("info1"); PamirsSession.getMessageHub().info("info2"); PamirsSession.getMessageHub().error("error1"); PamirsSession.getMessageHub().error("error2"); PamirsSession.getMessageHub().msg(new Message().msg("success1").setLevel(InformationLevelEnum.SUCCESS)); PamirsSession.getMessageHub().msg(new Message().msg("success2").setLevel(InformationLevelEnum.SUCCESS)); PamirsSession.getMessageHub().msg(new Message().msg("debug1").setLevel(InformationLevelEnum.DEBUG)); PamirsSession.getMessageHub().msg(new Message().msg("debug2").setLevel(InformationLevelEnum.DEBUG)); PamirsSession.getMessageHub().msg(new Message().msg("warn1").setLevel(InformationLevelEnum.WARN)); PamirsSession.getMessageHub().msg(new Message().msg("warn2").setLevel(InformationLevelEnum.WARN)); return data; } } 查询运行返回和效果 1)系统提示的返回结果 2)系统提示示例效果

    2024年5月14日
    1.7K00
  • 如何自定义SQL(Mapper)语句

    场景描述 在实际业务场景中,存在复杂SQL的情况,具体表现为: 单表单SQL满足不了的情况下 有复杂的Join关系或者子查询 复杂SQL的逻辑通过程序逻辑难以实现或实现代价较大 在此情况下,通过原生的mybatis/mybatis-plus, 自定义Mapper的方式实现业务功能 1、编写所需的Mapper SQL Mapper写法无限制,与使用原生的mybaits/mybaits-plus用法一样; Mapper(DAO)和SQL可以写在一个文件中,也分开写在两个文件中。 package pro.shushi.pamirs.demo.core.map; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; import java.util.Map; @Mapper public interface DemoItemMapper { @Select("<script>select sum(item_price) as itemPrice,sum(inventory_quantity) as inventoryQuantity,categoryId from ${demoItemTable} as core_demo_item ${where} group by category_id</script>") List<Map<String, Object>> groupByCategoryId(@Param("demoItemTable") String pamirsUserTable, @Param("where") String where); } 2.调用mapper 调用Mapper代码示例 package pro.shushi.pamirs.demo.core.map; import com.google.api.client.util.Lists; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.DemoItem; import pro.shushi.pamirs.framework.connectors.data.api.datasource.DsHintApi; import pro.shushi.pamirs.meta.api.core.orm.convert.DataConverter; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.common.spring.BeanDefinitionUtils; import java.util.List; import java.util.Map; @Component public class DemoItemDAO { public List<DemoItem> customSqlDemoItem(){ try (DsHintApi dsHint = DsHintApi.model(DemoItem.MODEL_MODEL)) { String demoItemTable = PamirsSession.getContext().getModelCache().get(DemoItem.MODEL_MODEL).getTable(); DemoItemMapper demoItemMapper = BeanDefinitionUtils.getBean(DemoItemMapper.class); String where = " where status = 'ACTIVE'"; List<Map<String, Object>> dataList = demoItemMapper.groupByCategoryId(demoItemTable,where); DataConverter persistenceDataConverter = BeanDefinitionUtils.getBean(DataConverter.class); return persistenceDataConverter.out(DemoItem.MODEL_MODEL, dataList); } return Lists.newArrayList(); } } 调用Mapper一些说明 启动类需要配置扫描包MapperScan @MapperScan(value = "pro.shushi", annotationClass = Mapper.class) @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, FreeMarkerAutoConfiguration.class}) public class DemoApplication { 调用Mapper接口的时候,需要指定数据源;即上述示例代码中的 DsHintApi dsHint = DsHintApi.model(DemoItem.MODEL_MODEL), 实际代码中使用 try-with-resources语法。 从Mapper返回的结果中获取数据 如果SQL Mapper中已定义了resultMap,调用Mapper(DAO)返回的就是Java对象 如果Mapper返回的是Map<String, Object>,则通过 DataConverter.out进行转化,参考上面的示例 其他参考:Oinone连接外部数据源方案:https://doc.oinone.top/backend/4562.html

    2023年11月27日
    1.9K00
  • 后端初始化工程启动

    在拿到Oinone初始化的后端工程体验时,配置修改点

    2023年11月3日
    1.9K00

Leave a Reply

Please Login to Comment