#
Update: for production environment, to avoid exposing the password in the command line, since you can query the processes with ps
, previous commands with history
, etc etc. You could:
- Create a script like this:
touch setEnv.sh
- Edit
setEnv.sh
to export the JASYPT_ENCRYPTOR_PASSWORD
variable#!/bin/bash
export JASYPT_ENCRYPTOR_PASSWORD=supersecretz
- Execute the file with
. setEnv.sh
- Run the app in background with
mvn spring-boot:run &
- Delete the file
setEnv.sh
- Unset the previous environment variable with:
unset JASYPT_ENCRYPTOR_PASSWORD
https://stackoverflow.com/questions/37404703/spring-boot-how-to-hide-passwords-in-properties-file
當(dāng)SPRING INTEGRATION的流程中從HTTP outboundGateway轉(zhuǎn)成JmsGateway時(shí),會(huì)報(bào)header的錯(cuò)誤,這時(shí)就要把相關(guān)多余的header移除。
.headerFilter("Api-Key", "Content-Type", "X-Powered-By", "Content-Language", "Transfer-Encoding", "Cache-Control", "Keep-Alive", "Set-Cookie")
https://stackoverflow.com/questions/50608415/cwsia0112e-the-property-name-keep-alive-is-not-a-valid-java-identifier
RestTemplate是Spring提供的用于訪問Rest服務(wù)的客戶端,
RestTemplate提供了多種便捷訪問遠(yuǎn)程Http服務(wù)的方法,能夠大大提高客戶端的編寫效率。
調(diào)用RestTemplate的默認(rèn)構(gòu)造函數(shù),RestTemplate對(duì)象在底層通過使用java.net包下的實(shí)現(xiàn)創(chuàng)建HTTP 請(qǐng)求,
可以通過使用ClientHttpRequestFactory指定不同的HTTP請(qǐng)求方式。
ClientHttpRequestFactory接口主要提供了兩種實(shí)現(xiàn)方式
1、一種是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)創(chuàng)建底層的Http請(qǐng)求連接。
2、一種方式是使用HttpComponentsClientHttpRequestFactory方式,底層使用HttpClient訪問遠(yuǎn)程的Http服務(wù),使用HttpClient可以配置連接池和證書等信息。
默認(rèn)的 RestTemplate 有個(gè)機(jī)制是請(qǐng)求狀態(tài)碼非200 就拋出異常,會(huì)中斷接下來的操作。如果不想中斷對(duì)結(jié)果數(shù)據(jù)得解析,可以通過覆蓋默認(rèn)的 ResponseErrorHandler ,見下面的示例,示例中的方法中基本都是空方法,只要對(duì)hasError修改下,讓他一直返回true,即是不檢查狀態(tài)碼及拋異常了。
package com.example.demo.web.config;
import java.io.IOException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) throws Exception {
RestTemplate restTemplate = new RestTemplate(factory);
ResponseErrorHandler responseErrorHandler = new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
return true;
}
@Override
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
}
};
restTemplate.setErrorHandler(responseErrorHandler);
return restTemplate;
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
//讀取超時(shí)5秒
factory.setReadTimeout(5000);
//連接超時(shí)15秒
factory.setConnectTimeout(15000);
return factory;
}
}
RestTemppate運(yùn)用實(shí)例
package com.example.demo.web.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.example.demo.domain.Book;
@RestController
public class TestBookController {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private RestTemplate restTemplate;
@GetMapping("/testaddbook")
public Book testAddBook() {
Book book = new Book();
ResponseEntity<Book> responseEntity = restTemplate.postForEntity( "http://localhost:8061/book", book , Book.class);
return responseEntity.getBody();
}
}
其他方法,catch
HttpStatusCodeException ,
e.getResponseBodyAsString()try {
ResponseEntity<Component> response = restTemplate.exchange(webSvcURL,
HttpMethod.POST,
requestEntity,
Component.class);
} catch (HttpStatusCodeException e) {
List<String> customHeader = e.getResponseHeaders().get("x-app-err-id");
String svcErrorMessageID = "";
if (customHeader != null) {
svcErrorMessageID = customHeader.get(0);
}
throw new CustomException(e.getMessage(), e, svcErrorMessageID);
// You can get the body too but you will have to deserialize it yourself
// e.getResponseBodyAsByteArray()
// e.getResponseBodyAsString()
}
https://stackoverflow.com/questions/7878002/resttemplate-handling-response-headers-body-in-exceptions-restclientexceptionhttps://stackoverflow.com/questions/38093388/spring-resttemplate-exception-handling/51805956#51805956
在SPRING INTEGRATION中,如果exception發(fā)生在各種thread里時(shí),如何將exception返回到指定的channel,之后再繞回到aggrator-channel中。
@Bean
public IntegrationFlow provisionUserFlow() {
return
IntegrationFlows.from("input.channel")
.publishSubscribeChannel(Executors.newCachedThreadPool(),
s -> s.applySequence(true)
.subscribe(f -> f.enrichHeaders(e -> e.header(MessageHeaders.ERROR_CHANNEL, "errorChannel", true))
.handle(provisionerA, "provision")
.channel("aggregatorChannel")
)
.subscribe(f -> f.enrichHeaders(e -> e.header(MessageHeaders.ERROR_CHANNEL, "errorChannel", true))
.handle(provisionerB, "provision")
.channel("aggregatorChannel"))
)
.get();
}
@Bean
public IntegrationFlow aggregateFlow() {
return IntegrationFlows.from("aggregatorChannel")
.channel( aggregatorChannel)
.aggregate( a -> a.processor( collect, "aggregatingMethod"))
.get();
}
@Transformer( inputChannel = "errorChannel", outputChannel = "aggregatorChannel")
public Message<?> errorChannelHandler(ErrorMessage errorMessage) throws RuntimeException {
Message<?> failedMessage = ((MessagingException) errorMessage.getPayload()).getFailedMessage();
Exception exception = (Exception) errorMessage.getPayload();
return MessageBuilder.withPayload( exception.getMessage())
.copyHeadersIfAbsent( failedMessage.getHeaders() )
.build();
}
https://stackoverflow.com/q/46495127/11790720
split-route-aggregate flow
split之后,可以將message分給不同的子flow處理,配置如下:
@Bean
public IntegrationFlow parallelSplitRouteAggregateFlow() {
return IntegrationFlows
.from(Http.inboundGateway("/trigger"))
.handle((p, h) -> Arrays.asList(1, 2, 3))
.split()
.channel(MessageChannels.executor(Executors.newCachedThreadPool()))
.<Integer, Boolean>route(o -> o % 2 == 0, m -> m
.subFlowMapping(true, sf -> sf.gateway(oddFlow()))
.subFlowMapping(false, sf -> sf.gateway(evenFlow())))
.aggregate()
.get();
}
@Bean
public IntegrationFlow oddFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "odd");
}
@Bean
public IntegrationFlow evenFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "even");
}
https://stackoverflow.com/questions/50121384/spring-integration-parallel-split-route-aggregate-flow-fails-due-to-one-way-mess
安裝:
wget -O jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
chmod +x ./jq
cp jq /usr/bin
摘要: 最近在公司用JUP框架做項(xiàng)目,發(fā)現(xiàn)這個(gè)框架是別人基于SpringSide封裝的,所以打算學(xué)習(xí)下,SpringSide,其中遇到了很多坑,做個(gè)記錄,網(wǎng)上關(guān)于這方面的資料都有些老了,而且SpringSide最新的版本是SpringSide-Utils,老一點(diǎn)的版本為v4.2.2.GA,以下分別對(duì)這兩個(gè)版本分別介紹下,主要內(nèi)容來自于網(wǎng)上。一些資料:Github源碼地址: https://gi...
閱讀全文
Spring Cloud |
你懂的 |
Keycloak |
微服務(wù)認(rèn)證授權(quán) |
Jenkins |
持續(xù)集成 |
SonarQube |
代碼質(zhì)量控制 |
https://gitee.com/itmuch/spring-cloud-yes
Keycloak是Jboss出品的做認(rèn)證和授權(quán)的WEB程序,根據(jù)OPENIDC協(xié)議,OPENID是做認(rèn)證,OAUTH2.0是做授權(quán),OPENIDC則將這兩者整合。
有提供一套WEB界面維護(hù)用戶、應(yīng)用與角色。
Ream則可認(rèn)為是多租戶,每個(gè)租戶的應(yīng)用和用戶數(shù)據(jù)是隔離的。
http://10.80.27.69:8180/auth/realms/quickstart/.well-known/openid-configuration 提供當(dāng)前所有的API節(jié)點(diǎn)。
get_access_token_from_public_client:
curl --location --request POST 'http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=alice' \
--data-urlencode 'password=123456' \
--data-urlencode 'client_id=app-springboot-public' \
--data-urlencode 'grant_type=password' \
| jq
./get_access_token_from_confidential_client.sh
curl --location --request POST 'http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=app-springboot-confidential' \
--data-urlencode 'client_secret=3acf7692-49cb-4c45-9943-6f3dba512dae' \
--data-urlencode 'grant_type=client_credentials' \
| jq
訪問一個(gè)ACCESS TYPE為Bare only的應(yīng)用的一個(gè)API:
access_token=$(curl \
-d "client_id=app-springboot-public" \
-d "username=alice" \
-d "password=123456" \
-d "grant_type=password" \
"http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/token" \
| jq -r '.access_token')
#echo $access_token
curl -H "Authorization: Bearer $access_token" 'http://10.80.27.69:8182/products' | jq
訪問用戶信息:
access_token=$(curl \
-d "client_id=app-springboot-public" \
-d "username=alice" \
-d "password=123456" \
-d "grant_type=password" \
"http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/token" | jq -r '.access_token')
curl -H "Authorization: Bearer $access_token" http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/userinfo | jq