{
  "author" : "Peter Cheung",
  "version" : "1.2.8",
  "userSecure" : "",
  "currTypeMapperGroupName" : "Default",
  "currTemplateGroupName" : "mybatis-util",
  "currColumnConfigGroupName" : "Default",
  "currGlobalConfigGroupName" : "Default",
  "typeMapper" : { },
  "template" : {
    "mybatis-config" : {
      "name" : "mybatis-config",
      "elementList" : [ {
        "name" : "banner.txt.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"banner.txt\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources\"))\n#[[${AnsiColor.GREEN}\n  ▄███████▄    ▄████████    ▄████████    ▄████████     ▄█    █▄      ▄████████  ███     █▄  ███▄▄▄▄      ▄██████▄\n  ███    ███   ███    ███   ███    ███   ███    ███   ███    ███     ███    ███ ███     ███ ███▀▀▀▀██▄   ███    ███\n  ███    ███   ███    █▀    ███    ███   ███    █▀    ███    ███     ███    █▀  ███     ███ ███    ███   ███    █▀\n  ███    ███  ▄███▄▄▄       ███▄▄▄▄██▀   ███         ▄███▄▄▄▄███▄▄  ▄███▄▄▄     ███     ███ ███    ███  ▄███\n  █████████▀  ▀███▀▀▀       ███▀▀▀▀█▄    ███        ▀▀███▀▀▀▀███▀  ▀▀███▀▀▀     ███     ███ ███    ███  ▀███  ████▄\n  ███          ███    █▄    ███    ███   ███     ▄█   ███    ███     ███    ███ ███     ███ ███    ███   ███    ███\n  ███          ███    ███   ███    ███   ███    ███   ███    ███     ███    ███ ███     ███ ███    ███   ███    ███\n ▄███▄         ██████████   ███    ███   ████████▀    ███    █▀      ██████████ █████████▀  ▀██    ██▀   ████████▀\n${AnsiStyle.BOLD}${AnsiColor.BRIGHT_MAGENTA}\nSPRING BOOT VERSION: ${spring-boot.version}\n${AnsiColor.BLACK}${AnsiStyle.NORMAL}]]#"
      }, {
        "name" : "logback.xml.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"logback-spring.xml\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources\"))\n#[[<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n    <contextName>logback-spring</contextName>\n    <property name=\"pattern\"\n              value=\"%d{yyyy-MM-dd HH:mm:ss.SSS,GMT+8} [%thread] %-5level %logger{50} - %msg %n\"/>\n    <property name=\"pattern-color\"\n              value=\"%yellow(%d{yyyy-MM-dd HH:mm:ss.SSS,GMT+8}) [%thread] %highlight(%-5level) %green(%logger{50}) - %highlight(%msg) %n\"/>\n    <property name=\"LOG_HOME\"\n              value=\"logs\"/>\n\n    <!-- 控制台输出-带颜色 -->\n    <appender name=\"console-with-color\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n            <pattern>${pattern-color}</pattern>\n        </encoder>\n    </appender>\n\n    <!-- 所有日志文件输出 -->\n    <appender name=\"file\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <fileNamePattern>${LOG_HOME}/%d.all.%i.log</fileNamePattern>\n            <!-- 日志文件最大的大小 -->\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>10MB</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n            <!--日志文件保留天数 -->\n            <maxHistory>30</maxHistory>\n        </rollingPolicy>\n        <encoder>\n            <pattern>${pattern}</pattern>\n        </encoder>\n    </appender>\n\n    <!--输出错误日志-->\n    <appender name=\"error\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <FileNamePattern>${LOG_HOME}/error/%d.error.%i.log</FileNamePattern>\n            <!-- 日志文件最大的大小 -->\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>10MB</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n            <!--日志文件保留天数 -->\n            <maxHistory>30</maxHistory>\n        </rollingPolicy>\n        <encoder>\n            <pattern>${pattern}</pattern>\n        </encoder>\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n            <level>ERROR</level>\n            <onMatch>ACCEPT</onMatch>\n            <onMismatch>DENY</onMismatch>\n        </filter>\n    </appender>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"console-with-color\"/>\n        <appender-ref ref=\"file\"/>\n        <appender-ref ref=\"error\"/>\n    </root>\n</configuration>]]#"
      }, {
        "name" : "pom.xml.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"pom.xml\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources/pom\"))\n#[[<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.7.14</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>路径</groupId>\n    <artifactId>包名</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>包名</name>\n    <description>包名</description>\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-web</artifactId>\n            </dependency>\n            <!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->\n            <dependency>\n                <groupId>cn.dev33</groupId>\n                <artifactId>sa-token-spring-boot-starter</artifactId>\n                <version>1.35.0.RC</version>\n            </dependency>\n            <!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->\n            <dependency>\n                <groupId>cn.dev33</groupId>\n                <artifactId>sa-token-redis-jackson</artifactId>\n                <version>1.35.0.RC</version>\n            </dependency>\n            <!--for string-->\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-lang3</artifactId>\n            </dependency>\n            <!--for map-->\n            <dependency>\n                <groupId>commons-beanutils</groupId>\n                <artifactId>commons-beanutils</artifactId>\n                <version>1.9.4</version>\n            </dependency>\n            <!--for sql-->\n            <dependency>\n                <groupId>org.mybatis.spring.boot</groupId>\n                <artifactId>mybatis-spring-boot-starter</artifactId>\n                <version>2.2.2</version>\n            </dependency>\n            <!--for page-->\n            <dependency>\n                <groupId>com.github.pagehelper</groupId>\n                <artifactId>pagehelper-spring-boot-starter</artifactId>\n                <version>1.4.1</version>\n            </dependency>\n            <!--character verification-->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-validation</artifactId>\n            </dependency>\n            <!--swagger3-->\n            <dependency>\n                <groupId>io.springfox</groupId>\n                <artifactId>springfox-boot-starter</artifactId>\n                <version>3.0.0</version>\n            </dependency>\n            <!-- knife4j -->\n            <dependency>\n                <groupId>com.github.xiaoymin</groupId>\n                <artifactId>knife4j-spring-boot-starter</artifactId>\n                <version>3.0.3</version>\n            </dependency>\n            <!--for mysql-->\n            <dependency>\n                <groupId>com.mysql</groupId>\n                <artifactId>mysql-connector-j</artifactId>\n                <scope>runtime</scope>\n            </dependency>\n            <!--lombok-->\n            <dependency>\n                <groupId>org.projectlombok</groupId>\n                <artifactId>lombok</artifactId>\n                <optional>true</optional>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-test</artifactId>\n                <scope>test</scope>\n            </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>]]#"
      }, {
        "name" : "banner.win.txt.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"banner.txt\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources\"))\n#[[${AnsiStyle.BOLD}${AnsiColor.BRIGHT_RED} ______             ______ _\n${AnsiColor.BRIGHT_RED}(_____ \\           / _____) |\n${AnsiColor.BRIGHT_YELLOW} _____) )___  ____| /     | | _   ____ _   _ ____   ____\n${AnsiColor.BRIGHT_GREEN}|  ____/ _  )/ ___) |     | || \\ / _  ) | | |  _ \\ / _  |\n${AnsiColor.BRIGHT_CYAN}| |   ( (/ /| |   | \\_____| | | ( (/ /| |_| | | | ( ( | |\n${AnsiColor.BRIGHT_MAGENTA}|_|    \\____)_|    \\______)_| |_|\\____)\\____|_| |_|\\_|| |\n${AnsiColor.BRIGHT_MAGENTA}                                                  (_____|\nSPRING BOOT VERSION: ${spring-boot.version}${AnsiStyle.NORMAL}]]#"
      }, {
        "name" : "application.yaml.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"application.yaml\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources\"))\nspring:\n  profiles:\n    active: test"
      }, {
        "name" : "application-dev.yaml.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"application-dev.yaml\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources\"))\nserver:\n  port: 8081\n\n# Sa-Token 配置 (文档: https://sa-token.cc)\nsa-token:\n  # token 名称(同时也是 cookie 名称)\n  token-name: satoken\n  # token 有效期(单位:秒) 默认30天,-1 代表永久有效,当前设置90天\n  timeout: 7776000\n  # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结\n  active-timeout: -1\n  # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)\n  is-concurrent: false\n  # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)\n  token-style: simple-uuid\n  # 是否输出操作日志\n  is-log: true\n  # 是否尝试从 cookie 里读取 Token,此值为 false 后,StpUtil.login(id) 登录时也不会再往前端注入Cookie\n  isReadCookie: false\n  # 是否尝试从 请求体 里读取 Token\n  isReadBody: false\n\nswagger:\n  enabled: false\n\nCrossOrigin:\n  enable: false\n\nspring:\n  # Redis配置\n  redis:\n    host: localhost\n    port: 6379\n    password:\n    # 操作0号数据库,默认有16个数据库\n    database: 0\n    lettuce:\n      pool:\n        # 最大连接数\n        max-active: 500\n        # 连接池最大阻塞等待时间\n        max-wait: 1000ms\n        # 连接池中的最大空闲连接\n        max-idle: 100\n        # 连接池中的最小空闲连接\n        min-idle: 0\n  # 配置文件上传大小限制\n  servlet:\n    multipart:\n      max-file-size: 200MB\n      max-request-size: 200MB\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n  datasource:\n    username: root\n    password: root\n    # useUnicode是否使用Unicode字符集\n    # characterEncoding 当useUnicode设置为true时,指定字符编码\n    # serverTimezone 时区\n    # allowMultiQueries 是否允许执行多行sql\n    # connectTimeout 和数据库服务器建立socket连接时的超时,单位:毫秒,0表示永不超时\n    # socketTimeout 操作(读写)超时,单位:毫秒,0表示永不超时\n    url: jdbc:mysql://127.0.0.1:3306/database?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&connectTimeout=60000&socketTimeout=60000\n    # 下面为连接池的补充设置,应用到上面所有数据源中\n    hikari:\n      # 自动提交事务\n      auto-commit: true\n      # 最小连接数\n      minimum-idle: 30\n      # 最大连接数\n      maximum-pool-size: 200\n      # 配置获取连接等待超时的时间\n      connection-timeout: 60000\n      # 配置一个连接在池中最小生存的时间,单位是毫秒\n      idle-timeout: 60000\n      # 验证连接的查询语句\n      connection-test-query: SELECT 1 FROM DUAL\n\nmybatis:\n  mapper-locations: classpath:mapper/*.xml\n  configuration:\n    # call-setters-on-nulls 参数的作用是查询的某一行某一列为null,是否返回\n    call-setters-on-nulls: true\n    # 禁用二级缓存\n    # cache-enabled: false\n    # 一级缓存指定为statement级别 效果为禁用一级缓存\n    # local-cache-scope: statement\n    # 日志\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n\npagehelper:\n  # 默认值 false,当值为true时,pageSize=0或者RowBounds limit=0查询全部结果(相当于没有执行分页查询,但是返回结果仍然是Page类型)\n  page-size-zero: false\n  # 指定数据库,可以不配置,pagehelper插件会自动检测数据库的类型\n  helperDialect: mysql\n  # 分页合理化参数默认 false,当该参数设置为true 时,pageNum <= 0 时,默认显示第一页,pageNum 超过 pageSize 时,显示最后一页\n  reasonable: false\n  # 分页插件会根据查询方法的参数中,自动根据params配置的字段中取值,找到合适的值会自动分页\n  supportMethodsArguments: false\n  # 为了支持 startPage(Object params) 方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值,可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值\n  params: count=countSql\n\nknife4j:\n  # 开启增强配置\n  enable: true\n  basic:\n    enable: true\n    # Basic认证用户名\n    username: root\n    # Basic认证密码\n    password: root"
      }, {
        "name" : "application-prod.yaml.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"application-prod.yaml\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources\"))\nserver:\n  port: 8081\n\nswagger:\n  enabled: false\n\nCrossOrigin:\n  enable: false\n\nspring:\n  # 配置文件上传大小限制\n  servlet:\n    multipart:\n      max-file-size: 200MB\n      max-request-size: 200MB\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n  datasource:\n    username: root\n    password: root\n    # useUnicode是否使用Unicode字符集\n    # characterEncoding 当useUnicode设置为true时,指定字符编码\n    # serverTimezone 时区\n    # allowMultiQueries 是否允许执行多行sql\n    # connectTimeout 和数据库服务器建立socket连接时的超时,单位:毫秒,0表示永不超时\n    # socketTimeout 操作(读写)超时,单位:毫秒,0表示永不超时\n    url: jdbc:mysql://127.0.0.1:3306/database?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&connectTimeout=60000&socketTimeout=60000\n    # 下面为连接池的补充设置,应用到上面所有数据源中\n    hikari:\n      # 自动提交事务\n      auto-commit: true\n      # 最小连接数\n      minimum-idle: 100\n      # 最大连接数\n      maximum-pool-size: 500\n      # 配置获取连接等待超时的时间\n      connection-timeout: 60000\n      # 配置一个连接在池中最小生存的时间,单位是毫秒\n      idle-timeout: 60000\n      # 验证连接的查询语句\n      connection-test-query: SELECT 1 FROM DUAL\n\nmybatis:\n  mapper-locations: classpath:mapper/*.xml\n  configuration:\n    # call-setters-on-nulls 参数的作用是查询的某一行某一列为null,是否返回\n    call-setters-on-nulls: true\n    # 禁用二级缓存\n    # cache-enabled: false\n    # 一级缓存指定为statement级别 效果为禁用一级缓存\n    # local-cache-scope: statement\n    # 日志\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n\npagehelper:\n  # 默认值 false,当值为true时,pageSize=0或者RowBounds limit=0查询全部结果(相当于没有执行分页查询,但是返回结果仍然是Page类型)\n  page-size-zero: false\n  # 指定数据库,可以不配置,pagehelper插件会自动检测数据库的类型\n  helperDialect: mysql\n  # 分页合理化参数默认 false,当该参数设置为true 时,pageNum <= 0 时,默认显示第一页,pageNum 超过 pageSize 时,显示最后一页\n  reasonable: false\n  # 分页插件会根据查询方法的参数中,自动根据params配置的字段中取值,找到合适的值会自动分页\n  supportMethodsArguments: false\n  # 为了支持 startPage(Object params) 方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值,可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值\n  params: count=countSql"
      }, {
        "name" : "application-test.yaml.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"application-test.yaml\"))\n$!callback.setSavePath($tool.append($modulePath, \"/src/main/resources\"))\nserver:\n  port: 8081\n\nswagger:\n  enabled: true\n\nCrossOrigin:\n  enable: true\n\nspring:\n  # 配置文件上传大小限制\n  servlet:\n    multipart:\n      max-file-size: 200MB\n      max-request-size: 200MB\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n  mvc:\n    pathmatch:\n      matching-strategy: ant_path_matcher\n  datasource:\n    username: root\n    password: root\n    # useUnicode是否使用Unicode字符集\n    # characterEncoding 当useUnicode设置为true时,指定字符编码\n    # serverTimezone 时区\n    # allowMultiQueries 是否允许执行多行sql\n    # connectTimeout 和数据库服务器建立socket连接时的超时,单位:毫秒,0表示永不超时\n    # socketTimeout 操作(读写)超时,单位:毫秒,0表示永不超时\n    url: jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&connectTimeout=60000&socketTimeout=60000\n    # 下面为连接池的补充设置,应用到上面所有数据源中\n    hikari:\n      # 自动提交事务\n      auto-commit: true\n      # 最小连接数\n      minimum-idle: 10\n      # 最大连接数\n      maximum-pool-size: 200\n      # 配置获取连接等待超时的时间\n      connection-timeout: 60000\n      # 配置一个连接在池中最小生存的时间,单位是毫秒\n      idle-timeout: 60000\n      # 验证连接的查询语句\n      connection-test-query: SELECT 1 FROM DUAL\n\nmybatis:\n  mapper-locations: classpath:mapper/*.xml\n  configuration:\n    # call-setters-on-nulls 参数的作用是查询的某一行某一列为null,是否返回\n    call-setters-on-nulls: true\n    # 禁用二级缓存\n    # cache-enabled: false\n    # 一级缓存指定为statement级别 效果为禁用一级缓存\n    # local-cache-scope: statement\n    # 日志\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n\npagehelper:\n  # 默认值 false,当值为true时,pageSize=0或者RowBounds limit=0查询全部结果(相当于没有执行分页查询,但是返回结果仍然是Page类型)\n  page-size-zero: false\n  # 指定数据库,可以不配置,pagehelper插件会自动检测数据库的类型\n  helperDialect: mysql\n  # 分页合理化参数默认 false,当该参数设置为true 时,pageNum <= 0 时,默认显示第一页,pageNum 超过 pageSize 时,显示最后一页\n  reasonable: false\n  # 分页插件会根据查询方法的参数中,自动根据params配置的字段中取值,找到合适的值会自动分页\n  supportMethodsArguments: false\n  # 为了支持 startPage(Object params) 方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值,可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值\n  params: count=countSql"
      }, {
        "name" : "swagger.java.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"SwaggerConfig.java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/config/swagger\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}config.swagger;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport springfox.documentation.builders.RequestHandlerSelectors;\nimport springfox.documentation.service.ApiInfo;\nimport springfox.documentation.service.Contact;\nimport springfox.documentation.spi.DocumentationType;\nimport springfox.documentation.spring.web.plugins.Docket;\n\nimport java.util.ArrayList;\n\nimport static #if($tableInfo.savePackageName)$!{tableInfo.savePackageName}.#{end}config.constant.Constant.SWAGGER_PACKAGE;\n\n/**\n * Swagger配置\n *\n * @author $!author\n * @since $!time.currTime()\n */\n@Slf4j\n@Configuration\n@EnableKnife4j\npublic class SwaggerConfig {\n    /**\n     * 用于读取配置文件 swagger 属性是否开启\n     */\n    @Value(\"${swagger.enabled}\")\n    private boolean swaggerEnabled;\n\n    @Bean\n    public Docket docket() {\n        return new Docket(DocumentationType.OAS_30)\n                .apiInfo(apiInfo())\n                // 是否开启swagger\n                .enable(swaggerEnabled)\n                .select()\n                // 过滤条件,扫描指定路径下的文件\n                .apis(RequestHandlerSelectors.basePackage(SWAGGER_PACKAGE))\n                // 指定路径处理,PathSelectors.any()代表不过滤任何路径\n                //.paths(PathSelectors.any())\n                .build();\n    }\n\n    /**\n     * 作者信息\n     */\n    private ApiInfo apiInfo() {\n        Contact contact = new Contact(\"Peter Cheung\", \"https://github.com/PerCheung\", \"c2243736958@qq.com\");\n        return new ApiInfo(\n                \"Knife4j\",\n                \"Knife4j接口文档\",\n                \"v1.0\",\n                \"https://github.com/PerCheung\",\n                contact,\n                \"Apache 2.0\",\n                \"https://www.apache.org/licenses/LICENSE-2.0\",\n                new ArrayList<>()\n        );\n    }\n}\n"
      }, {
        "name" : "constant.java.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"Constant.java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/config/constant\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}config.constant;\n\n\n/**\n * 常量\n *\n * @author $!author\n * @since $!time.currTime()\n */\npublic interface Constant {\n    /**\n     * 全局异常包路径\n     */\n    String PACKAGE_NAME = \"#if($tableInfo.savePackageName)$!{tableInfo.savePackageName}#{end}\";\n\n    /**\n     * swagger扫描包\n     */\n    String SWAGGER_PACKAGE = \"#if($tableInfo.savePackageName)$!{tableInfo.savePackageName}.#{end}controller\";\n\n    /**\n     * 文件保存位置\n     */\n    String SAVE_FOLDER = \"file\";\n\n}\n"
      }, {
        "name" : "crossorigininterceptor.java.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"CrossOriginInterceptor.java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/config/crossorigin\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}config.crossorigin;\n\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.servlet.HandlerInterceptor;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n/**\n * 跨域拦截器\n *\n * @author $!author\n * @since $!time.currTime()\n */\npublic class CrossOriginInterceptor implements HandlerInterceptor {\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {\n        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, \"*\");\n        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, \"GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH, TRACE\");\n        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, \"*\");\n        response.setHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, \"3600\");\n        // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态\n        if (request.getMethod().equals(HttpMethod.OPTIONS.name())) {\n            response.setStatus(HttpStatus.OK.value());\n        }\n        return true;\n    }\n}"
      }, {
        "name" : "crossorigininterceptorconfig.java.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"CrossOriginInterceptorConfig.java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/config/crossorigin\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}config.crossorigin;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * 跨域拦截器的开启配置类\n *\n * @author $!author\n * @since $!time.currTime()\n */\n@Slf4j\n@Configuration\npublic class CrossOriginInterceptorConfig implements WebMvcConfigurer {\n    /**\n     * 决定是否需要跨域\n     */\n    @Value(\"${CrossOrigin.enable}\")\n    private boolean enableCrossOrigin;\n\n    @Bean\n    public HandlerInterceptor getHandlerCrossOriginInterceptor() {\n        return new CrossOriginInterceptor();\n    }\n\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        if (enableCrossOrigin) {\n            // 跨域拦截器\n            registry.addInterceptor(getHandlerCrossOriginInterceptor())\n                    // 拦截的路径\n                    .addPathPatterns(\"/api/**\");\n        }\n    }\n}"
      }, {
        "name" : "redisconfig.java.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"RedisConfig.java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/config/redis\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}config.redis;\n\nimport org.springframework.cache.annotation.CachingConfigurerSupport;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n/**\n * Redis配置类,更换默认序列化器\n *\n * @author $!author\n * @since $!time.currTime()\n */\n@Configuration\npublic class RedisConfig extends CachingConfigurerSupport {\n    /**\n     * 创建 RedisTemplate Bean,用于操作 Redis 数据库。\n     *\n     * @param connectionFactory Redis 连接工厂\n     * @return RedisTemplate 实例\n     */\n    @Bean\n    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {\n        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();\n        // 设置 RedisTemplate 的连接工厂\n        redisTemplate.setConnectionFactory(connectionFactory);\n        // 创建 StringRedisSerializer 实例,用于序列化和反序列化 Redis 的键和哈希键\n        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();\n        // 创建 GenericJackson2JsonRedisSerializer 实例,用于序列化和反序列化 Redis 的值和哈希值\n        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();\n        // 设置默认序列化器为 StringRedisSerializer\n        redisTemplate.setDefaultSerializer(stringRedisSerializer);\n        // 设置 RedisTemplate 的键序列化器为 StringRedisSerializer\n        redisTemplate.setKeySerializer(stringRedisSerializer);\n        // 设置 RedisTemplate 的哈希键序列化器为 StringRedisSerializer\n        redisTemplate.setHashKeySerializer(stringRedisSerializer);\n        // 设置 RedisTemplate 的值序列化器为 GenericJackson2JsonRedisSerializer\n        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);\n        // 设置 RedisTemplate 的哈希值序列化器为 GenericJackson2JsonRedisSerializer\n        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);\n        return redisTemplate;\n    }\n}"
      }, {
        "name" : "allexceptionhandle.java.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"AllExceptionHandle.java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/config/exception\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}config.exception;\n\nimport cn.dev33.satoken.exception.NotBasicAuthException;\nimport cn.dev33.satoken.exception.NotLoginException;\nimport cn.dev33.satoken.exception.NotRoleException;\nimport #if($tableInfo.savePackageName)$!{tableInfo.savePackageName}.#{end}util.R;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport javax.validation.ValidationException;\nimport java.io.ByteArrayOutputStream;\nimport java.io.PrintStream;\n\nimport static #if($tableInfo.savePackageName)$!{tableInfo.savePackageName}.#{end}config.constant.Constant.PACKAGE_NAME;\n\n/**\n * 全局异常统一处理\n *\n * @author $!author\n * @since $!time.currTime()\n */\n@Slf4j\n@ControllerAdvice\n@ResponseBody\npublic class AllExceptionHandle {\n    /**\n     * 登录权限校验异常\n     */\n    @ExceptionHandler({NotLoginException.class})\n    public R unauthorized(Exception e) {\n        return R.unauthorized().data(sub(e(e)));\n    }\n\n    /**\n     * 权限不足\n     */\n    @ExceptionHandler({NotRoleException.class, NotBasicAuthException.class})\n    public R forbidden(Exception e) {\n        return R.forbidden().data(sub(e(e)));\n    }\n\n    /**\n     * 校验传参\n     */\n    @ExceptionHandler(ValidationException.class)\n    public R handleBadRequest(Exception e) {\n        return R.badRequest().data(sub(e(e)));\n    }\n\n    /**\n     * 全局异常处理\n     */\n    @ExceptionHandler(Exception.class)\n    public R exception(Exception e) {\n        return R.exp().data(sub(e(e)));\n    }\n\n    /**\n     * 异常信息处理主体方法\n     *\n     * @param e 异常对象\n     * @return 异常解析信息\n     */\n    public String e(Exception e) {\n        log.error(\"全局异常处理\");\n        //打印详细报错日志\n        log.error(\"详细信息如下================================\");\n        ByteArrayOutputStream printStackTrace = new ByteArrayOutputStream();\n        e.printStackTrace(new PrintStream(printStackTrace));\n        log.error(String.valueOf(printStackTrace));\n        log.error(\"==========================================\");\n        //错误信息\n        StringBuilder errorMessage = new StringBuilder();\n        errorMessage.append(e);\n        if (StringUtils.isBlank(e.getMessage())) {\n            //处理\n            log.error(String.valueOf(errorMessage));\n            return String.valueOf(errorMessage);\n        }\n        StackTraceElement[] stackTrace = e.getStackTrace();\n        for (StackTraceElement stackTraceElement : stackTrace) {\n            String className = stackTraceElement.getClassName();\n            if (className.startsWith(PACKAGE_NAME)) {\n                //报错类名称\n                String errorName = \";\" + stackTraceElement.getClassName();\n                errorMessage.append(errorName);\n                //报错类行号\n                String errorLineNumber = \":\" + stackTraceElement.getLineNumber();\n                errorMessage.append(errorLineNumber);\n                //处理\n                log.error(String.valueOf(errorMessage));\n                return String.valueOf(errorMessage);\n            }\n        }\n        //处理\n        log.error(String.valueOf(errorMessage));\n        return String.valueOf(errorMessage);\n    }\n\n    /**\n     * 字符串截取,只保留错误信息\n     */\n    private String sub(String error) {\n        log.error(\"进入sub()方法的完整错误信息-\" + error);\n        String sub = \"Exception: \";\n        // 查找第一个Exception: 的索引\n        int index = error.indexOf(sub);\n        if (index != -1) {\n            // 使用substring方法截取子字符串\n            return error.substring(index + sub.length());\n        } else {\n            return error;\n        }\n    }\n}"
      }, {
        "name" : "satokenconfigure.java.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"SaTokenConfigure.java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/config/token\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}config.token;\n\nimport cn.dev33.satoken.interceptor.SaInterceptor;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * 提供注解鉴权\n *\n * @author $!author\n * @since $!time.currTime()\n */\n@Configuration\npublic class SaTokenConfigure implements WebMvcConfigurer {\n    // 注册 Sa-Token 拦截器,打开注解式鉴权功能\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        // 注册 Sa-Token 拦截器,打开注解式鉴权功能\n        registry.addInterceptor(new SaInterceptor()).addPathPatterns(\"/api/**\");\n    }\n}"
      }, {
        "name" : "stpinterfaceimpl.java.vm",
        "code" : "##设置回调\n$!callback.setFileName($tool.append(\"StpInterfaceImpl.java\"))\n$!callback.setSavePath($tool.append($tableInfo.savePath, \"/config/token\"))\n\n#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}config.token;\n\nimport cn.dev33.satoken.stp.StpInterface;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 提供权限认证\n *\n * @author $!author\n * @since $!time.currTime()\n */\n@Service\npublic class StpInterfaceImpl implements StpInterface {\n\n    /**\n     * 返回一个账号所拥有的权限码集合\n     */\n    @Override\n    public List<String> getPermissionList(Object loginId, String loginType) {\n        // 本 list 仅做模拟,实际项目中要根据具体业务逻辑来查询权限\n        List<String> permissionList = new ArrayList<>();\n        permissionList.add(\"权限一\");\n        permissionList.add(\"权限二\");\n        permissionList.add(\"权限三\");\n        return permissionList;\n    }\n\n    /**\n     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)\n     */\n    @Override\n    public List<String> getRoleList(Object loginId, String loginType) {\n        // 本 list 仅做模拟,实际项目中要根据具体业务逻辑来查询角色\n        List<String> roleList = new ArrayList<>();\n        roleList.add(\"管理员\");\n        return roleList;\n    }\n}"
      } ]
    }
  },
  "columnConfig" : { },
  "globalConfig" : { }
}