需求場景
在項目中,我們本身使用的是SQL Server 數據庫,在某些功能之中需要用到Sybase數據庫,Sybase數據庫是JNDI在Web容器中進行配置的,.對於外部Tomcat的JNDI配置可以參考我的文章使用JNDI連接數據庫。此時我們開發環境使用SpringBoot內嵌Tomcat無法連接Sybase,那麼我們就需要在SpringBoot內嵌Tomcat中配置Sybase的內嵌資源,並且在其它環境中使用Web容器的JNDI.代碼示例
解決方案
- 在配置文件中配置Sybase 連接信息;
jndiConfig:
jndiList: # 此處應當與JNDIResource屬性名相同
- jndiName: jdbc/Sybase_iws_ref
auth: Container
type: javax.sql.DataSource
driverClassName: com.sybase.jdbc4.jdbc.SybDriver
url: jdbc:sybase:Tds:127.0.0.1:4101?ServiceName=db_iws_ref
username: root
password: root@
maxActive: 100
maxIdle: 30
maxWait: 10000
- jndiName: jdbc/Sybase_claims
auth: Container
type: javax.sql.DataSource
driverClassName: com.sybase.jdbc4.jdbc.SybDriver
url: jdbc:sybase:Tds:127.0.0.1:4101?ServiceName=db_claims
username: root
password: root@
maxActive: 100
maxIdle: 30
maxWait: 10000
JNDI:
Sybase:
CLAIMS: java:comp/env/jdbc/Sybase_claims
DB_IWS_REF: java:comp/env/jdbc/Sybase_iws_ref
- 封裝連接實體
JNDIProperties.java
package com.frank.db.config;
import org.springframework.stereotype.Component;
import java.util.Objects;
public class JNDIProperties {
private String jndiName;
private String auth;
private String type;
private String driverClassName;
private String url;
private String username;
private String password;
private String maxActive;
private String maxIdle;
private String maxWait;
public String getJndiName() {
return jndiName;
}
public void setJndiName(String jndiName) {
this.jndiName = jndiName;
}
public String getAuth() {
return auth;
}
public void setAuth(String auth) {
this.auth = auth;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMaxActive() {
return maxActive;
}
public void setMaxActive(String maxActive) {
this.maxActive = maxActive;
}
public String getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(String maxIdle) {
this.maxIdle = maxIdle;
}
public String getMaxWait() {
return maxWait;
}
public void setMaxWait(String maxWait) {
this.maxWait = maxWait;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JNDIProperties that = (JNDIProperties) o;
return Objects.equals(jndiName, that.jndiName) &&
Objects.equals(auth, that.auth) &&
Objects.equals(type, that.type) &&
Objects.equals(driverClassName, that.driverClassName) &&
Objects.equals(url, that.url) &&
Objects.equals(username, that.username) &&
Objects.equals(password, that.password) &&
Objects.equals(maxActive, that.maxActive) &&
Objects.equals(maxIdle, that.maxIdle) &&
Objects.equals(maxWait, that.maxWait);
}
@Override
public int hashCode() {
return Objects.hash(jndiName, auth, type, driverClassName, url, username, password, maxActive, maxIdle, maxWait);
}
@Override
public String toString() {
return "JNDIProperties{" +
"jndiName='" + jndiName + '\'' +
", auth='" + auth + '\'' +
", type='" + type + '\'' +
", driverClassName='" + driverClassName + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
", maxActive='" + maxActive + '\'' +
", maxIdle='" + maxIdle + '\'' +
", maxWait='" + maxWait + '\'' +
'}';
}
}
JNDIResource.java
package com.frank.db.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "jndiConfig")
public class JNDIResource {
private List<JNDIProperties> jndiList = new ArrayList<>();
public List<JNDIProperties> getJndiList() {
return jndiList;
}
public void setJndiList(List<JNDIProperties> jndiList) {
this.jndiList = jndiList;
}
}
- 在SpringBoot內嵌Tomcat配置JNDI
JDNIConfig.java
package com.frank.db.config;
import com.frank.db.common.CommonConstant;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.ContextResource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Configuration
public class JDNIConfig{
@Resource
private JNDIResource jNDIResource;
// 只有在dev環境下加載此Bean
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
@Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
@Override
protected void postProcessContext(Context context) {
if(jNDIResource.getJndiList().isEmpty()){
return;
}
for (JNDIProperties jNDIProperties :jNDIResource.getJndiList()){
ContextResource resource = new ContextResource();
resource.setName(jNDIProperties.getJndiName());
resource.setType(jNDIProperties.getType());
resource.setProperty(CommonConstant.DATA_FACTORY, "org.apache.tomcat.jdbc.pool.DataSourceFactory");
resource.setProperty(CommonConstant.DATA_DRIVER_CLASS_NAME, jNDIProperties.getDriverClassName());
resource.setProperty(CommonConstant.DATA_URL, jNDIProperties.getUrl());
resource.setProperty(CommonConstant.DATA_USER_NAME, jNDIProperties.getUsername());
resource.setProperty(CommonConstant.DATA_PASSWORD,jNDIProperties.getPassword());
context.getNamingResources().addResource(resource);
}
}
};
}
}
- Db工具類
package com.frank.db.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class DBUtils {
private static InitialContext context;
@Value(value="${JNDI.Sybase.CLAIMS}")
public String SYBASE_CLAIMS = "jdbc/Sybase_claims";
@Value(value="${JNDI.Sybase.DB_IWS_REF}")
public String SYBASE_DB_IWS_REF = "jdbc/Sybase_iws_ref";
static final Logger log = LoggerFactory.getLogger("ServiceLog");
private DBUtils() {
super();
}
public Connection getConnection(String jndiName) throws Exception {
DataSource ds = getDataSource(jndiName);
if(ds==null) {
throw new RuntimeException("Can't get valid datasource, jndiName:"+jndiName);
}
return ds.getConnection();
}
public synchronized DataSource getDataSource(String jndiName) {
DataSource ds = null;
try {
if (context == null)
context = new InitialContext();
ds = (DataSource) context.lookup(jndiName);
} catch (NamingException e) {
e.printStackTrace();
}
return ds;
}
public List<Map<String, Object>> excuteSQL(String jndiName,String sql) throws Exception {
Connection conn = getConnection(jndiName);
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.executeQuery();
ResultSet rs = stmt.getResultSet();
List<Map<String, Object>> rsList = new ArrayList<Map<String, Object>>();
if(rs ==null) {
return null;
}
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
Map<String,Object> rowData = new HashMap<String,Object>();
for (int i = 1; i <= columnCount; i++) {
rowData.put(metaData.getColumnName(i), rs.getObject(i));
}
rsList.add(rowData);
}
stmt.close();
conn.close();
return rsList;
}
public List<Object> excuteSQL2(String jndiName,String sql) throws Exception {
List<Object> rsList=new ArrayList<>();
Connection conn = getConnection(jndiName);
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.executeQuery();
ResultSet rs = stmt.getResultSet();
if(rs ==null) {
return null;
}
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
Map<String,Object> rowData = new HashMap<String,Object>();
for (int i = 1; i <= columnCount; i++) {
rsList.add(rs.getObject(i));
}
}
stmt.close();
conn.close();
return rsList;
}
public void excuteSP(String jndiName,String sql) throws Exception {
Connection conn = getConnection(jndiName);
CallableStatement call = conn.prepareCall(sql);
call.execute();
call.close();
conn.close();
}
}
- 測試
package com.frank.db.controller;
import com.frank.db.service.FdHNWFormService;
import com.frank.db.utils.DBUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
public class DBController {
@Autowired
DBUtils dbUtils;
@Autowired
private FdHNWFormService fdHNWFormService;
@RequestMapping("/mssql")
@ResponseBody
public String factoryBean(long rowId) {
return fdHNWFormService.selectByPrimaryKey(rowId).toString();
}
@RequestMapping("/sybaseRef")
@ResponseBody
public String sybaseRefTest() {
try {
String sql = "select * from tuser_authority where system_type='DCM' and user_id='so'";
List<Map<String, Object>> maps = dbUtils.excuteSQL(dbUtils.SYBASE_DB_IWS_REF, sql);
return maps.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping("/sybaseClaim")
@ResponseBody
public String sybaseClaimTest() {
try {
String sql = "select * from tfunc_level where system_type = 'DCM'";
List<Map<String, Object>> maps = dbUtils.excuteSQL(dbUtils.SYBASE_CLAIMS, sql);
return maps.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}