<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    paulwong

    #

    SPRING BOOT OAUTH2 + KEYCLOAK - service to service call

    employee-service調用department-service,如果要按OAUTH2.0流程,只需要提供client-id和client-secrect即可。在KEYCLOAK中引入service-account,即配置該employee-service時,取消standard-flow,同時激活service-account。
    employee-service的application.yaml文件,其中的public-key要從KEYCLOAK中取
    server:
       port: 8090
    # Can be set to false to disable security during local development
    rest:
       security:
          enabled: true
          #issuer-uri: http://localhost:8080/auth/realms/dev
          api-matcher: /api/**
          cors:
             allowed-origins: '*'
             allowed-headers: '*'
             allowed-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
             max-age: 3600

    security:
       oauth2:
          resource:
             filter-order: 3
             id: test-employee-service
             token-info-uri: ${rest.security.issuer-uri}/protocol/openid-connect/token/introspect
             user-info-uri: ${rest.security.issuer-uri}/protocol/openid-connect/userinfo
             jwt:
                key-value: | 
                   -----BEGIN PUBLIC KEY-----
                   MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB
                   -----END PUBLIC KEY-----

    # To access another secured micro-service
          client:
             client-id: test-employee-service
             #client-secret: 25c33006-e1b9-4fc2-a6b9-c43dbc41ecd0
             user-authorization-uri: ${rest.security.issuer-uri}/protocol/openid-connect/auth
             access-token-uri: ${rest.security.issuer-uri}/protocol/openid-connect/token
             scope: openid
             grant-type: client_credentials
             is-client-only: true

    #Logging Configuration
    logging:
       level:
          org.springframework.boot.autoconfigure.logging: INFO
          org.springframework.security: DEBUG
          org.arun: DEBUG
          root: INFO

    application-dev.yaml
    rest:
       security:
          issuer-uri: http://10.80.27.69:8180/auth/realms/quickstart

    department-service:
       url: http://10.80.27.69:8095/api/departments/1

    security:
       oauth2:
          client:
             client-secret: db25cdbd-605b-429d-bd92-96705bdf1474

    department-service的application.yaml
    server:
       port: 8095
    # Can be set to false to disable security during local development
    rest:
       security:
          enabled: true
          #issuer-uri: http://localhost:8080/auth/realms/dev
          api-matcher: /api/**
          cors:
             allowed-origins: '*'
             allowed-headers: '*'
             allowed-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
             max-age: 3600

    security:
       oauth2:
          resource:
             filter-order: 3
             id: test-department-service
             token-info-uri: ${rest.security.issuer-uri}/protocol/openid-connect/token/introspect
             user-info-uri: ${rest.security.issuer-uri}/protocol/openid-connect/userinfo
             jwt:
                key-value: | 
                   -----BEGIN PUBLIC KEY-----
                   MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB
                   -----END PUBLIC KEY-----

    #Logging Configuration
    logging:
       level:
          org.springframework.boot.autoconfigure.logging: INFO
          org.springframework.security: DEBUG
          org.arun: DEBUG
          root: INFO

    application-dev.yaml
    rest:
       security:
          issuer-uri: http://10.80.27.69:8180/auth/realms/quickstart

    employee-service的pom.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.18.RELEASE</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>org.arun.springoauth</groupId>
        <artifactId>spring-oauth2-employee-service</artifactId>
        <version>1.0.0</version>
        <name>spring-oauth2-employee-service</name>
        <description>Employee Service</description>

        <properties>
            <java.version>1.8</java.version>
            <spring-boot.version>2.1.18.RELEASE</spring-boot.version>
        </properties>

        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>

            <dependency>
                <groupId>org.springframework.security.oauth.boot</groupId>
                <artifactId>spring-security-oauth2-autoconfigure</artifactId>
                <!-- <version>2.1.18.RELEASE</version> -->
                <version>${spring-boot.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>

        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <layout>ZIP</layout>
                        <excludes>
                            <exclude>
                                <groupId>*</groupId>
                                <artifactId>*</artifactId>
                            </exclude>
                        </excludes>
                        <includes>
                            <include>
                                <groupId>com.paul</groupId>
                            </include>
                        </includes>
                    </configuration>
                </plugin>
            </plugins>
        </build>

    </project>

    將jwt格式的access_token轉成Authentication的類JwtAccessTokenCustomizer
    package org.arun.springoauth.employee.config;

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.security.oauth2.resource.JwtAccessTokenConverterConfigurer;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.AuthorityUtils;
    import org.springframework.security.oauth2.provider.OAuth2Authentication;
    import org.springframework.security.oauth2.provider.OAuth2Request;
    import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
    import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

    @Configuration
    public class JwtAccessTokenCustomizer extends DefaultAccessTokenConverter implements JwtAccessTokenConverterConfigurer {

        private static final Logger LOG = LoggerFactory.getLogger(JwtAccessTokenCustomizer.class);

        private static final String CLIENT_NAME_ELEMENT_IN_JWT = "resource_access";

        private static final String ROLE_ELEMENT_IN_JWT = "roles";

        private ObjectMapper mapper;

        @Autowired
        public JwtAccessTokenCustomizer(ObjectMapper mapper) {
            this.mapper = mapper;
            LOG.info("Initialized {}", JwtAccessTokenCustomizer.class.getSimpleName());
        }

        @Override
        public void configure(JwtAccessTokenConverter converter) {
            converter.setAccessTokenConverter(this);
            LOG.info("Configured {}", JwtAccessTokenConverter.class.getSimpleName());
        }

        /**
         * Spring oauth2 expects roles under authorities element in tokenMap, but
         * keycloak provides it under resource_access. Hence extractAuthentication
         * method is overriden to extract roles from resource_access.
         *
         * 
    @return OAuth2Authentication with authorities for given application
         
    */
        @Override
        public OAuth2Authentication extractAuthentication(Map<String, ?> tokenMap) {
            LOG.debug("Begin extractAuthentication: tokenMap = {}", tokenMap);
            JsonNode token = mapper.convertValue(tokenMap, JsonNode.class);
            Set<String> audienceList = extractClients(token); // extracting client names
            List<GrantedAuthority> authorities = extractRoles(token); // extracting client roles

            OAuth2Authentication authentication = super.extractAuthentication(tokenMap);
            OAuth2Request oAuth2Request = authentication.getOAuth2Request();

            OAuth2Request request = new OAuth2Request(oAuth2Request.getRequestParameters(), oAuth2Request.getClientId(),
                    authorities, true, oAuth2Request.getScope(), audienceList, nullnullnull);

            Authentication usernamePasswordAuthentication = new UsernamePasswordAuthenticationToken(
                    authentication.getPrincipal(), "N/A", authorities);
            LOG.debug("End extractAuthentication");
            return new OAuth2Authentication(request, usernamePasswordAuthentication);
        }

        private List<GrantedAuthority> extractRoles(JsonNode jwt) {
            LOG.debug("Begin extractRoles: jwt = {}", jwt);
            Set<String> rolesWithPrefix = new HashSet<>();

            jwt.path(CLIENT_NAME_ELEMENT_IN_JWT).elements().forEachRemaining(e -> e.path(ROLE_ELEMENT_IN_JWT).elements()
                    .forEachRemaining(r -> rolesWithPrefix.add("ROLE_" + r.asText())));

            final List<GrantedAuthority> authorityList = AuthorityUtils
                    .createAuthorityList(rolesWithPrefix.toArray(new String[0]));
            LOG.debug("End extractRoles: roles = {}", authorityList);
            return authorityList;
        }

        private Set<String> extractClients(JsonNode jwt) {
            LOG.debug("Begin extractClients: jwt = {}", jwt);
            if (jwt.has(CLIENT_NAME_ELEMENT_IN_JWT)) {
                JsonNode resourceAccessJsonNode = jwt.path(CLIENT_NAME_ELEMENT_IN_JWT);
                final Set<String> clientNames = new HashSet<>();
                resourceAccessJsonNode.fieldNames().forEachRemaining(clientNames::add);

                LOG.debug("End extractClients: clients = {}", clientNames);
                return clientNames;

            } else {
                throw new IllegalArgumentException(
                        "Expected element " + CLIENT_NAME_ELEMENT_IN_JWT + " not found in token");
            }

        }

    }



    Reference
    https://medium.com/@bcarunmail/securing-rest-api-using-keycloak-and-spring-oauth2-6ddf3a1efcc2



    posted @ 2021-10-26 17:06 paulwong 閱讀(572) | 評論 (0)編輯 收藏

    Nginx代理轉發SFTP

    https://blog.csdn.net/qq_27127385/article/details/103666143

    posted @ 2021-10-15 10:04 paulwong 閱讀(350) | 評論 (0)編輯 收藏

    使用REST API與KEYCLOAK進行OUATH2協議的登錄認證

    KEYCLOAK是一套用戶、WEB API登錄管理,授權管理的WEB應用。
    如果要訪問受KEYCLOAK保護的REST API服務,則需要夾帶一個ACCESS_TOKEN。

    前端頁面:
    • 前端頁面一般是給用戶使用的,則需要用戶輸入在KEYCLOAK中有效的用戶名和密碼,并提供CALL BAK的URL,提交給KEYCLOAK
      http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/auth?client_id=app-springboot-confidential&redirect_uri=http://10.80.27.69:8183/&response_type=code&scope=openid
    • 如果KEYCLOAK驗證通過,則通知頁面重導向回調的URL,并附上code=xxx,此code則是AUTHORIZATION_CODE
      http://10.80.27.69:8183/?session_state=2ad9ab98-6c39-43a8-872f-2112c27b74df&code=3f48ce19-58f9-45d9-8c09-30d492bf4b24.2ad9ab98-6c39-43a8-872f-2112c27b74df.bd7526ef-b1bf-447f-baef-b7dfd6f0df93
    • 回調的URL對應的SERVELET,取得AUTHORIZATION_CODE,并加上client_id和client_secrect,調用KEYLOAK的取ACCESS_TOKEN的HTTP API,取得ACCESS_TOKEN,返回給頁面
      http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/token
      client_id=app-springboot-confidential&client_secret=3acf7692-49cb-4c45-9943-6f3dba512dae&redirect_uri=http://10.80.27.69:8183/&grant_type=authorization_code&code=cc7ac566-90f9-404e-b88e-fa28037b07d1.591311e1-5380-46a2-9363-834f17337922.bd7526ef-b1bf-447f-baef-b7dfd6f0df93
    • 頁面保存此ACCESS_TOKEN,就可以調用后臺的各種API獲取數據
      {
          "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJGSjg2R2NGM2pUYk5MT2NvNE52WmtVQ0lVbWZZQ3FvcXRPUWVNZmJoTmxFIn0.eyJleHAiOjE2MzQwMjA4ODksImlhdCI6MTYzNDAyMDU4OSwianRpIjoiNDAwOTQ4ZmQtMGU0MS00YWRjLTlhY2MtMzczZWM2NDVhNzM5IiwiaXNzIjoiaHR0cDovLzEwLjgwLjI3LjY5OjgxODAvYXV0aC9yZWFsbXMvcXVpY2tzdGFydCIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJkZGVkMDA2YS0xY2QxLTRjODUtOTQ1MS0wMjFlZmY3OTFiMmUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhcHAtc3ByaW5nYm9vdC1jb25maWRlbnRpYWwiLCJzZXNzaW9uX3N0YXRlIjoiYzRlN2QzYTgtMDg2My00OTAwLTkxZmEtMGExYmFmYmRlNGU3IiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYXBwLXNwcmluZ2Jvb3QtY29uZmlkZW50aWFsIjp7InJvbGVzIjpbInVtYV9wcm90ZWN0aW9uIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImNsaWVudElkIjoiYXBwLXNwcmluZ2Jvb3QtY29uZmlkZW50aWFsIiwiY2xpZW50SG9zdCI6IjEwLjEwLjIwLjU3IiwidXNlcl9uYW1lIjoic2VydmljZS1hY2NvdW50LWFwcC1zcHJpbmdib290LWNvbmZpZGVudGlhbCIsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC1hcHAtc3ByaW5nYm9vdC1jb25maWRlbnRpYWwiLCJjbGllbnRBZGRyZXNzIjoiMTAuMTAuMjAuNTcifQ.Ut6aZ6E1d4Esz0gRv2ubxdvrxmGvZLHHZepD5pnGxlqb_yZ4Q82TdGTG0iL4JJn2NH3QAU501dhzzuv6-OT9BUBKP-4ufyKv2DxSvt3GgdN30au5JsATHFyOWuuZGRBd3iWcynf9u3OJnSkHEnrIwRYatgndLzy8dy3AeqF12CI",
          "expires_in": 300,
          "refresh_expires_in": 600,
          "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2MTlhMmJjOS0yMWIwLTRmNGMtODI4OC1kNTJmMjA3OWEzY2EifQ.eyJleHAiOjE2MzQwMjExODksImlhdCI6MTYzNDAyMDU4OSwianRpIjoiYTM0NTQ1MTYtMzc3NC00YmRlLTgzOTMtN2QyMTdkZjdkZmJkIiwiaXNzIjoiaHR0cDovLzEwLjgwLjI3LjY5OjgxODAvYXV0aC9yZWFsbXMvcXVpY2tzdGFydCIsImF1ZCI6Imh0dHA6Ly8xMC44MC4yNy42OTo4MTgwL2F1dGgvcmVhbG1zL3F1aWNrc3RhcnQiLCJzdWIiOiJkZGVkMDA2YS0xY2QxLTRjODUtOTQ1MS0wMjFlZmY3OTFiMmUiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoiYXBwLXNwcmluZ2Jvb3QtY29uZmlkZW50aWFsIiwic2Vzc2lvbl9zdGF0ZSI6ImM0ZTdkM2E4LTA4NjMtNDkwMC05MWZhLTBhMWJhZmJkZTRlNyIsInNjb3BlIjoicHJvZmlsZSBlbWFpbCJ9.QhjkJBGz5UvwBF7xHM7_V_yjfF0lrA_EWzAVdFf-BRI",
          "token_type": "bearer",
          "not-before-policy": 0,
          "session_state": "c4e7d3a8-0863-4900-91fa-0a1bafbde4e7",
          "scope": "profile email"
      }
    • 這就是authorization_code流程

    后端服務:
    • 如果是在一個API中要請求另外一個API的數據,不存在具體用戶的情況
    • 需提供如下參數:client_id、client_secrect和grant_type,且grant_type=client_credentials,調用KEYLOAK的取ACCESS_TOKEN的HTTP API,取得ACCESS_TOKEN
      http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/token
      client_id=app-springboot-confidential&client_secret=3acf7692-49cb-4c45-9943-6f3dba512dae&grant_type=client_credentials
    • 再將此ACCESS_TOKEN以Bearer TOKEN的方式調用別的的API
    • 這就是client_credentials流程

    驗證Access Token和獲取Token元信息:
    • http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/token/introspect
      client_id=app-springboot-confidential&client_secret=3acf7692-49cb-4c45-9943-6f3dba512dae
    • Access Token無效時返回:
      {
          "active": false
      }

    刷新Token:
    • http://10.80.27.69:8180/auth/realms/quickstart/protocol/openid-connect/token
      client_id=app-springboot-confidential&client_secret=3acf7692-49cb-4c45-9943-6f3dba512dae&grant_type=refresh_token&refresh_token=asdfasd
    • 返回
      {
          "access_token": "eyJhbGciOiJSUzI1NiIsIn",
          "expires_in": 300,
          "refresh_expires_in": 1800,
          "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOi",
          "token_type": "Bearer",
          "not-before-policy": 1610728470,
          "session_state": "c1273eb5-f922-420c-b23a-854be9735c1d",
          "scope": "profile email"
      }



    Reference:
    https://blog.csdn.net/nklinsirui/article/details/112706006

    https://www.baeldung.com/?s=keycloak

    https://www.doag.org/formes/pubfiles/11143470/2019-NN-Sebastien_Blanc-Easily_Secure_your_Microservices_with_Keycloak-Praesentation.pdf




    posted @ 2021-10-12 14:40 paulwong 閱讀(781) | 評論 (0)編輯 收藏

    Enterprise Architect VS Solution Architect VS Software Architect

    • Enterprise Architect
      定義企業的大概方向
    • Solution Architect
      定義系統使用哪些框架技術
    • Software  Architect
      定義系統行為
    • Technical  Architect
      定義有關部署所使用服務器

    https://stackoverflow.com/questions/524941/whats-the-difference-between-solutions-architect-and-applications-architect

    https://www.youtube.com/watch?v=zB9WuYE1REI

    posted @ 2021-10-11 15:29 paulwong 閱讀(167) | 評論 (0)編輯 收藏

    SPRING CLOUD CONFIG有界面的配置管理中心




    https://dyc87112.github.io/spring-cloud-config-admin/

    posted @ 2021-10-07 16:55 paulwong 閱讀(292) | 評論 (0)編輯 收藏

    開源流程引擎哪個好,如何選型?

    https://zhuanlan.zhihu.com/p/369761832

    posted @ 2021-09-27 11:05 paulwong 閱讀(239) | 評論 (0)編輯 收藏

    Camunda流程引擎

    http://shaochenfeng.com/camunda/

    posted @ 2021-09-27 10:55 paulwong 閱讀(174) | 評論 (0)編輯 收藏

    Camunda/Flowable/Activiti技術發展史

    https://blog.csdn.net/qq_30739519/article/details/86583765

    posted @ 2021-09-27 10:45 paulwong 閱讀(342) | 評論 (0)編輯 收藏

    SPRING INTEGRATION - ENRICH

    enrich時可以發起一個子流程,取得結果后再設置回當前的對象中。

    package org.springframework.integration.stackoverflow.enricher;

    import java.util.List;
    import java.util.Map;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.http.HttpMethod;
    import org.springframework.integration.dsl.IntegrationFlow;
    import org.springframework.integration.dsl.IntegrationFlows;
    import org.springframework.integration.dsl.Transformers;
    import org.springframework.integration.http.dsl.Http;
    import org.springframework.web.client.RestTemplate;

    @SpringBootApplication
    public class SpringIntegrationEnricherApplication {

        public static void main(String[] args) {
            SpringApplication.run(SpringIntegrationEnricherApplication.class, args);
        }

        @Bean
        public IntegrationFlow jsonEnricherFlow(RestTemplate restTemplate) {
            return IntegrationFlows.from(Function.class)
                    .transform(Transformers.fromJson(Map.class))
                    .enrich((enricher) -> enricher
                            .<Map<String, ?>>requestPayload((message) ->
                                    ((List<?>) message.getPayload().get("attributeIds"))
                                            .stream()
                                            .map(Object::toString)
                                            .collect(Collectors.joining(",")))
                            .requestSubFlow((subFlow) ->
                                    subFlow.handle(
                                            Http.outboundGateway("/attributes?id={ids}", restTemplate)
                                                    .httpMethod(HttpMethod.GET)
                                                    .expectedResponseType(Map.class)
                                                    .uriVariable("ids", "payload")))
                            .propertyExpression("attributes", "payload.attributes"))
                    .<Map<String, ?>, Map<String, ?>>transform(
                            (payload) -> {
                                payload.remove("attributeIds");
                                return payload;
                            })
                    .transform(Transformers.toJson())
                    .get();
        }

    }

    https://stackoverflow.com/questions/58205432/spring-integration-enrich-transform-message-using-rest-call

    https://www.tabnine.com/web/assistant/code/rs/5c781b6ae70f87000197ab9f#L312

    posted @ 2021-09-21 13:40 paulwong 閱讀(269) | 評論 (0)編輯 收藏

    Java9之HttpClient

    Java9之HttpClientAPI實戰詳解
    https://blog.csdn.net/u014042066/article/details/78153653

    Java 9 揭秘(14. HTTP/2 Client API)
    https://www.cnblogs.com/IcanFixIt/p/7229611.html

    Java JDK11(Java11)中設置HttpClient允許不安全的HTTPS連接
    https://www.cjavapy.com/article/84/

    posted @ 2021-09-03 14:04 paulwong 閱讀(211) | 評論 (0)編輯 收藏

    僅列出標題
    共115頁: First 上一頁 6 7 8 9 10 11 12 13 14 下一頁 Last 
    主站蜘蛛池模板: 亚洲色一色噜一噜噜噜| 国产成人久久AV免费| 亚洲香蕉在线观看| 亚洲国产AV一区二区三区四区| 日韩免费a级在线观看| 亚洲AV无码男人的天堂| 国产无遮挡又黄又爽免费视频| 亚洲精品国产av成拍色拍| 亚洲精品在线不卡| 最近最新MV在线观看免费高清| 亚洲高清免费在线观看| 久久免费精品一区二区| 亚洲av成人综合网| 国产精品免费大片| 好吊妞在线成人免费| 浮力影院亚洲国产第一页| 亚洲综合一区国产精品| 国产精品久久久久影院免费| 亚洲成AV人片一区二区密柚| 99国产精品免费观看视频| 苍井空亚洲精品AA片在线播放| 亚洲av无码成人影院一区| 中国国产高清免费av片| 亚洲va无码手机在线电影| 免费乱码中文字幕网站| 人体大胆做受免费视频| 亚洲国产精品成人久久久| 国产美女无遮挡免费视频 | 自拍偷区亚洲国内自拍| 久久91亚洲人成电影网站| 亚洲AV一宅男色影视| 亚洲中文久久精品无码1| 久久久久久亚洲AV无码专区| 久久精品国产亚洲精品| 亚洲人成在线电影| 亚洲国产精品久久久久| 久久亚洲精品无码av| 免费成人午夜视频| 一本大道一卡二大卡三卡免费| 91九色老熟女免费资源站 | 免费人成毛片动漫在线播放|