前提: 公司数据库,项目都放在 云服务器上跑的,今天为了XXX安全,然后禁止公网访问数据库,如果需要访问 可以通过SSH隧道。
思路: 网上百度了很多,大部分都是写一个DBUtils 工具类,我觉得改动太大了,没采用,看了其它大神的文章,找到了用 监听器的方式,来监听端口,然后映射远程端口 把SSH隧道 当作 类似跳板机 的东西 来使用
所以 我们只需要监听本地的 端口 就可以了,一旦监听到了 替换 数据库连接的一些配置就可以了
-------------------------- 开始 动手了
1、需要导入一个第三方的包 帮我们连接SSH
com.jcraft
jsch
0.1.53
2、创建一个类实现 监听器的接口(有servlet自带的 ServletContextListener,也有spring 的 TestExecutionListener ,是有所区别的 暂时留一个坑)
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyListener implements ServletContextListener {
private SSHConnection conexionssh;
public MyListener() {
super();
}
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("Context initialized ... !");
try {
conexionssh = new SSHConnection(); // 监听到了 就装配文件
} catch (Throwable e) {
e.printStackTrace(); // error connecting SSH server
}
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("Context destroyed ... !");
conexionssh.closeSSH(); // disconnect
}
}
@WebListener 是servlet3.1之后新增的一个注解,可以不用再web.xml配置监听器
3、 装配SSH的 一些配置,继续New一个类
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.util.Properties;
public class SSHConnection {
private final static int LOCAl_PORT = 3307;
private final static int REMOTE_PORT = 3306;
private final static int SSH_REMOTE_PORT = sshport;
private final static String SSH_USER = "sshuser";
private final static String SSH_PASSWORD = "sshpassword";
private final static String SSH_REMOTE_SERVER = "sshurl";
private final static String MYSQL_REMOTE_SERVER = "数据库地址";
private Session sesion; //represents each ssh session
public void closeSSH() {
sesion.disconnect();
}
public SSHConnection() throws Throwable {
JSch jsch = null;
jsch = new JSch();
sesion = jsch.getSession(SSH_USER, SSH_REMOTE_SERVER, SSH_REMOTE_PORT);
sesion.setPassword(SSH_PASSWORD);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sesion.setConfig(config);
sesion.connect(); //ssh connection established!
//by security policy, you must connect through a fowarded port
sesion.setPortForwardingL(LOCAl_PORT, MYSQL_REMOTE_SERVER, REMOTE_PORT);
}
}
4、数据库的配置 稍微修改下 ,只需要修改地址
jdbc.url=jdbc:mysql://123456.mysql.rds.aliyuncs.com:3306/数据库名称?useUnicode=true&characterEncoding=utf8
替换为
jdbc.url=jdbc:mysql://127.0.0.1:3307/数据库名称?useUnicode\=true&characterEncoding\=utf8
127.0.0.1 表示本地 3307表示 本地的端口(可随意指定 3300 也可以 等等)
但是,但是 ,细心的你会发现,如果是junit 单元测试,依然行不通, 因为 我的容器是内嵌的Jetty类似于Tomcat ,junit只会读取applicationContext.xml,并不会加载 监听器, 所以 现在开始填补选择继承监听器的坑。
因为junit @Test 是Spring 的东西,So选择监听器的时候可以选择实现Spring的监听器 TestExecutionListener 接口
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyContextListener implements TestExecutionListener {
private SSHConnection conexionssh;
public MyContextListener() {
super();
}
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("Context initialized ... !");
try {
conexionssh = new SSHConnection();
} catch (Throwable e) {
e.printStackTrace(); // error connecting SSH server
}
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("Context destroyed ... !");
conexionssh.closeSSH(); // disconnect
}
@Override
public void beforeTestClass(TestContext testContext) throws Exception {
}
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
System.out.println("Context initialized ... !");
try {
conexionssh = new SSHConnection();
} catch (Throwable e) {
e.printStackTrace(); // error connecting SSH server
}
}
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
}
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
}
@Override
public void afterTestClass(TestContext testContext) throws Exception {
}
}
然后在 test类配置
@RunWith(SpringJUnit4ClassRunner.class) //启动必备
@ContextConfiguration(locations = {"classpath:applicationContext.xml"}) //启动的时候读取文件
@TestExecutionListeners(listeners = { MyContextListener.class, DependencyInjectionTestExecutionListener.class }) //启动的时候获取监听器
public class TestEmployee {
xxx 要测试的东西
}
但是,但是,但是 我的项目 又启动不起来了。。。
为什么呢,因为 项目已启动 首先读取web.xml配置 里面会配置
在配置数据库连接池的时候,因为是JDBC链接的,所以要读取 db.properties文件,但是这时候 url地址 是 本地的。。 监听器又没办法启动, 所以导致数据库连接失败 。。。
Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Could not create connection to database server. Attempted reconnect 3 times. Giving up.)