Как установить значение URL JDBC по умолчанию в консоли H2 с помощью весенней загрузки - PullRequest
2 голосов
/ 21 мая 2019

Я включил консоль H2 при весенней загрузке. Тем не менее, когда я открываю страницу подключения консоли, URL по умолчанию сохраняется в истории консоли H2. Как настроить проект так, чтобы при запуске проекта URL-адрес совпадал с spring.datasource.url ? В настоящее время я устанавливаю URL в консоли вручную, но мне бы хотелось, чтобы он автоматически настраивался самим проектом.

YAML:

spring:
  h2:
    console:
      enabled: true
      path: /admin/h2


  datasource:
    url: jdbc:h2:mem:foobar

Обновление: Я знаю, что последние настройки соединения сохраняются в ~ / .h2.server.properties, но мне нужно установить свойства из запускаемого приложения, потенциально переключаясь между несколькими из них

1 Ответ

3 голосов
/ 30 мая 2019

Нет крюка для заполнения настроек.

Хорошая новость заключается в том, что мы можем изменить это с помощью небольшого кода.

Текущее состояние

Экран входа в систему создается в WebApp.index()

String[] settingNames = server.getSettingNames();
String setting = attributes.getProperty("setting");
if (setting == null && settingNames.length > 0) {
    setting = settingNames[0];
}
String combobox = getComboBox(settingNames, setting);
session.put("settingsList", combobox);
ConnectionInfo info = server.getSetting(setting);
if (info == null) {
    info = new ConnectionInfo();
}
session.put("setting", PageParser.escapeHtmlData(setting));
session.put("name", PageParser.escapeHtmlData(setting));
session.put("driver", PageParser.escapeHtmlData(info.driver));
session.put("url", PageParser.escapeHtmlData(info.url));
session.put("user", PageParser.escapeHtmlData(info.user));
return "index.jsp";

Мы хотим подключиться к server.getSettingNames(), а именно к server.getSettings(), используемому внизу.

synchronized ArrayList<ConnectionInfo> getSettings() {
    ArrayList<ConnectionInfo> settings = new ArrayList<>();
    if (connInfoMap.size() == 0) {
        Properties prop = loadProperties();
        if (prop.size() == 0) {
            for (String gen : GENERIC) {
                ConnectionInfo info = new ConnectionInfo(gen);
                settings.add(info);
                updateSetting(info);
            }
        } else {
            for (int i = 0;; i++) {
                String data = prop.getProperty(Integer.toString(i));
                if (data == null) {
                    break;
                }
                ConnectionInfo info = new ConnectionInfo(data);
                settings.add(info);
                updateSetting(info);
            }
        }
    } else {
        settings.addAll(connInfoMap.values());
    }
    Collections.sort(settings);
    return settings;
}

План

  • отключить ServletRegistrationBean<WebServlet> созданный H2ConsoleAutoConfiguration
  • замените его нашим классом конфигурации с подклассом WebServlet
  • наш CustomH2WebServlet переопределит init и зарегистрирует CustomH2WebServer (подкласс WebServer)
  • в CustomH2WebServer мы переопределяем getSettings() и все готово

Код

@EnableConfigurationProperties({H2ConsoleProperties.class, DataSourceProperties.class})
@Configuration
public class H2Config {

    private final H2ConsoleProperties h2ConsoleProperties;

    private final DataSourceProperties dataSourceProperties;

    public H2Config(H2ConsoleProperties h2ConsoleProperties, DataSourceProperties dataSourceProperties) {
        this.h2ConsoleProperties = h2ConsoleProperties;
        this.dataSourceProperties = dataSourceProperties;
    }

    @Bean
    public ServletRegistrationBean<WebServlet> h2Console() {
        String path = this.h2ConsoleProperties.getPath();
        String urlMapping = path + (path.endsWith("/") ? "*" : "/*");
        ServletRegistrationBean<WebServlet> registration = new ServletRegistrationBean<>(
                new CustomH2WebServlet(this.dataSourceProperties.getUrl()), urlMapping);
        H2ConsoleProperties.Settings settings = this.h2ConsoleProperties.getSettings();
        if (settings.isTrace()) {
            registration.addInitParameter("trace", "");
        }
        if (settings.isWebAllowOthers()) {
            registration.addInitParameter("webAllowOthers", "");
        }
        return registration;
    }
}

package org.h2.server.web;

import javax.servlet.ServletConfig;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Enumeration;

public class CustomH2WebServlet extends WebServlet {

    private final String dbUrl;

    public CustomH2WebServlet(String dbUrl) {
        this.dbUrl = dbUrl;
    }

    @Override
    public void init() {
        ServletConfig config = getServletConfig();
        Enumeration<?> en = config.getInitParameterNames();
        ArrayList<String> list = new ArrayList<>();
        while (en.hasMoreElements()) {
            String name = en.nextElement().toString();
            String value = config.getInitParameter(name);
            if (!name.startsWith("-")) {
                name = "-" + name;
            }
            list.add(name);
            if (value.length() > 0) {
                list.add(value);
            }
        }
        String[] args = list.toArray(new String[0]);
        WebServer server = new CustomH2WebServer(dbUrl);
        server.setAllowChunked(false);
        server.init(args);
        setServerWithReflection(this, server);
    }

    private static void setServerWithReflection(final WebServlet classInstance, final WebServer newValue) {
        try {
            final Field field = WebServlet.class.getDeclaredField("server");
            field.setAccessible(true);
            field.set(classInstance, newValue);
        }
        catch (SecurityException|NoSuchFieldException|IllegalArgumentException|IllegalAccessException ex) {
            throw new RuntimeException(ex);
        }
    }
}
package org.h2.server.web;

import java.util.ArrayList;
import java.util.Collections;

class CustomH2WebServer extends WebServer {

    private final String connectionInfo;

    CustomH2WebServer(String dbUrl) {

        this.connectionInfo = "Test H2 (Embedded)|org.h2.Driver|" +dbUrl+"|sa";
    }

    synchronized ArrayList<ConnectionInfo> getSettings() {
        ArrayList<ConnectionInfo> settings = new ArrayList<>();
        ConnectionInfo info = new ConnectionInfo(connectionInfo);
        settings.add(info);
        updateSetting(info);
        Collections.sort(settings);
        return settings;
    }
}
spring.h2.console.enabled=false
spring.datasource.url=jdbc:h2:mem:foobar

Все прошло гладко, кроме одного частного поля, которое нужно было установить с помощью отражения.

Приведенный код работает с H2 1.4.199

...