SpringBoot內嵌Tomcat JNDI配置

需求場景

在項目中,我們本身使用的是SQL Server 數據庫,在某些功能之中需要用到Sybase數據庫,Sybase數據庫是JNDI在Web容器中進行配置的,.對於外部Tomcat的JNDI配置可以參考我的文章使用JNDI連接數據庫。此時我們開發環境使用SpringBoot內嵌Tomcat無法連接Sybase,那麼我們就需要在SpringBoot內嵌Tomcat中配置Sybase的內嵌資源,並且在其它環境中使用Web容器的JNDI.代碼示例

解決方案

  1. 在配置文件中配置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
  1. 封裝連接實體
    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;
    }
}

  1. 在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);
                }

            }
        };
    }

}

  1. 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();
	}

	
}
  1. 測試
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;
    }


}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章