@Configuration
public class RestClientConfig {
@Bean
public RestTemplate restTemplate() throws Exception {
// 1. 載入我們剛剛建立的 TrustStore (只信任公司內部憑證)
KeyStore trustStore = KeyStore.getInstance("JKS");
// 將 internal_truststore.jks 放在 src/main/resources 下
try (InputStream is = new ClassPathResource("internal_truststore.jks").getInputStream()) {
trustStore.load(is, "changeit".toCharArray());
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
// 2. 配置 OkHttpClient (局部配置,不影響 JBoss 其他應用)
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0])
.connectionPool(new ConnectionPool(100, 5, TimeUnit.MINUTES)) // 建立連線池
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
// 3. 封裝進 RestTemplate
return new RestTemplate(new OkHttp3ClientHttpRequestFactory(okHttpClient));
}
}
QENvbmZpZ3VyYXRpb24KCnB1YmxpYyBjbGFzcyBSZXN0Q2xpZW50Q29uZmlnIHsKCgoKICAgIEBCZWFuCgogICAgcHVibGljIFJlc3RUZW1wbGF0ZSByZXN0VGVtcGxhdGUoKSB0aHJvd3MgRXhjZXB0aW9uIHsKCiAgICAgICAgLy8gMS4g6LyJ5YWl5oiR5YCR5Ymb5Ymb5bu656uL55qEIFRydXN0U3RvcmUgKOWPquS/oeS7u+WFrOWPuOWFp+mDqOaGkeitiSkKCiAgICAgICAgS2V5U3RvcmUgdHJ1c3RTdG9yZSA9IEtleVN0b3JlLmdldEluc3RhbmNlKCJKS1MiKTsKCiAgICAgICAgLy8g5bCHIGludGVybmFsX3RydXN0c3RvcmUuamtzIOaUvuWcqCBzcmMvbWFpbi9yZXNvdXJjZXMg5LiLCgogICAgICAgIHRyeSAoSW5wdXRTdHJlYW0gaXMgPSBuZXcgQ2xhc3NQYXRoUmVzb3VyY2UoImludGVybmFsX3RydXN0c3RvcmUuamtzIikuZ2V0SW5wdXRTdHJlYW0oKSkgewoKICAgICAgICAgICAgdHJ1c3RTdG9yZS5sb2FkKGlzLCAiY2hhbmdlaXQiLnRvQ2hhckFycmF5KCkpOwoKICAgICAgICB9CgoKCiAgICAgICAgVHJ1c3RNYW5hZ2VyRmFjdG9yeSB0bWYgPSBUcnVzdE1hbmFnZXJGYWN0b3J5LmdldEluc3RhbmNlKFRydXN0TWFuYWdlckZhY3RvcnkuZ2V0RGVmYXVsdEFsZ29yaXRobSgpKTsKCiAgICAgICAgdG1mLmluaXQodHJ1c3RTdG9yZSk7CgoKCiAgICAgICAgU1NMQ29udGV4dCBzc2xDb250ZXh0ID0gU1NMQ29udGV4dC5nZXRJbnN0YW5jZSgiVExTIik7CgogICAgICAgIHNzbENvbnRleHQuaW5pdChudWxsLCB0bWYuZ2V0VHJ1c3RNYW5hZ2VycygpLCBuZXcgU2VjdXJlUmFuZG9tKCkpOwoKCgogICAgICAgIC8vIDIuIOmFjee9riBPa0h0dHBDbGllbnQgKOWxgOmDqOmFjee9ru+8jOS4jeW9semfvyBKQm9zcyDlhbbku5bmh4nnlKgpCgogICAgICAgIE9rSHR0cENsaWVudCBva0h0dHBDbGllbnQgPSBuZXcgT2tIdHRwQ2xpZW50LkJ1aWxkZXIoKQoKICAgICAgICAgICAgICAgIC5zc2xTb2NrZXRGYWN0b3J5KHNzbENvbnRleHQuZ2V0U29ja2V0RmFjdG9yeSgpLCAoWDUwOVRydXN0TWFuYWdlcikgdG1mLmdldFRydXN0TWFuYWdlcnMoKVswXSkKCiAgICAgICAgICAgICAgICAuY29ubmVjdGlvblBvb2wobmV3IENvbm5lY3Rpb25Qb29sKDEwMCwgNSwgVGltZVVuaXQuTUlOVVRFUykpIC8vIOW7uueri+mAo+e3muaxoAoKICAgICAgICAgICAgICAgIC5jb25uZWN0VGltZW91dCg1LCBUaW1lVW5pdC5TRUNPTkRTKQoKICAgICAgICAgICAgICAgIC5yZWFkVGltZW91dCgxMCwgVGltZVVuaXQuU0VDT05EUykKCiAgICAgICAgICAgICAgICAuYnVpbGQoKTsKCgoKICAgICAgICAvLyAzLiDlsIHoo53pgLIgUmVzdFRlbXBsYXRlCgogICAgICAgIHJldHVybiBuZXcgUmVzdFRlbXBsYXRlKG5ldyBPa0h0dHAzQ2xpZW50SHR0cFJlcXVlc3RGYWN0b3J5KG9rSHR0cENsaWVudCkpOwoKICAgIH0KCn0K