I have enable the H2 console in spring boot. However, when I open the console connection page the default url is the one staved in the H2 console history. How can i configu
There is no hook provided to fill in settings.
The good news is that we can change that with a bit of code.
Current state
The Login screen is created in 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";
We want to tap into server.getSettingNames()
, and precisely into server.getSettings()
used underneath.
synchronized ArrayList getSettings() {
ArrayList 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;
}
The plan
ServletRegistrationBean
created by H2ConsoleAutoConfiguration
WebServlet
CustomH2WebServlet
will override init
and register CustomH2WebServer
(subclass of WebServer
)CustomH2WebServer
we override getSettings()
and we are doneThe Code
@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 h2Console() {
String path = this.h2ConsoleProperties.getPath();
String urlMapping = path + (path.endsWith("/") ? "*" : "/*");
ServletRegistrationBean 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 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 getSettings() {
ArrayList 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
Everything went smoolthly, except of one private field that needed to be set via reflection.
The code provided works with H2 1.4.199