最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringCloud?Gateway實(shí)現(xiàn)API接口加解密

 更新時(shí)間:2022年06月14日 14:08:02   作者:small_to_large  
這篇文章主要為大家介紹了SpringCloud?Gateway如何實(shí)現(xiàn)API接口加解密的,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定的幫助,需要的可以參考一下

接口范圍

所有GET請(qǐng)求 白名單除外

body 體 是 application_json 和 application_json_utf8 的 POST請(qǐng)求 白名單除外

POST url傳參也支持 白名單除外

啟用禁用/版本

后端提供獨(dú)立接口(或者現(xiàn)有接口)查詢是否需要啟用加密功能(如果后端啟用了,前端請(qǐng)求被攔截修改為為啟用,接口也無(wú)法訪問(wèn)回報(bào)解密錯(cuò)誤),此接口明文傳輸

請(qǐng)求頭增加一個(gè)加密版本字段,標(biāo)識(shí)當(dāng)前的加密算法版本:crypto-version: 1.0.0

加密算法

考慮到全局加密,使用AES加密方式性能更高

加密字符串:原始數(shù)據(jù) > AES加密后的字節(jié)數(shù)組 > Base64編碼處理

解密字符串:Base64密文 > AES密文 -> 原始字符串

AES加密細(xì)節(jié)

aesKey:32/16 位由后端同一生成

iv:aesKey

mode:CBC

padding:pkcs7

js例子

//加密
static encryptAES(data, key) {
  const dataBytes = CryptoJS.enc.Utf8.parse(data);
  const keyBytes = CryptoJS.enc.Utf8.parse(key);
  const encrypted = CryptoJS.AES.encrypt(dataBytes, keyBytes, {
    iv: keyBytes,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });
  return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}

報(bào)文格式

GET

url:/app/xx/xx?xx=1

加密處理

秘鑰:xxxxxxxxxxxxxxxx

加密文本:{"xx":1}

密文:xq4YR89LgUs4V5N5juKgW5hIsiOsCxBOwzX632S8NV4=

加密后的請(qǐng)求

/app/xx/xx?data=xq4YR89LgUs4V5N5juKgW5hIsiOsCxBOwzX632S8NV4=

POST

url:/app/xx/xx/xxx

json body:

{"xxx1":"111","xxx2":"huawei","xxx3":"789","xxx4":101,"xxx5":2}

加密處理

秘鑰:xxxxxxxxxxxxxxxx

加密文本

{"xxx1":"111","xxx2":"huawei","xxx3":"789","xxx4":101,"xxx5":2}

密文:1oUTYvWfyaeTJ5/wJTVBqUv0Dz0IAUQTZtxSKY9WLZZl8pILP2Sozk5yOYg9I1WTvzgbbGRDGcWV1ASpYykyS1Fq5cT8s3aLXQ6NMo0AaMOC9L0aVpR863qWso5O8aG3

加密后的請(qǐng)求*

json body:

{

"data": "1oUTYvWfyaeTJ5/wJTVBqUv0Dz0IAUQTZtxSKY9WLZZl8pILP2Sozk5yOYg9I1WTvzgbbGRDGcWV1ASpYykyS1Fq5cT8s3aLXQ6NMo0AaMOjt4G9dK0WwhMGZofYuBKmdF27R8Qkr3VtZvjadtvBazJurITyE7hFcr43nlHSL5E="

}

POST url傳參 和GET格式一致

網(wǎng)關(guān)實(shí)現(xiàn)細(xì)節(jié)代碼

基于GlobalFilter 接口包裝請(qǐng)求request和響應(yīng)response,先列出關(guān)鍵代碼,完整代碼見(jiàn)文末

filter過(guò)濾器請(qǐng)求配置和請(qǐng)求方式分發(fā)

 @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (!cryptoProperties.isEnabled()) {
            return chain.filter(exchange);
        }
        ServerHttpRequest request = exchange.getRequest();
        //校驗(yàn)請(qǐng)求路徑跳過(guò)加密
        String originalRequestUrl = RequestProvider.getOriginalRequestUrl(exchange);
        String path = exchange.getRequest().getURI().getPath();
        if (isSkip(path) || isSkip(originalRequestUrl)) {
            return chain.filter(exchange);
        }

        HttpHeaders headers = request.getHeaders();
        MediaType contentType = headers.getContentType();

        //后期算法升級(jí)擴(kuò)展,暫時(shí)只判斷是否相等
        if (!cryptoProperties.getCryptoVersion().equals(headers.getFirst(cryptoProperties.getCryptoVersionHeader()))) {
            return Mono.error(new CryptoException("加密版本不支持"));
        }

        if (request.getMethod() == HttpMethod.GET) {
            return this.handleGetReq(exchange, chain);
        } else if (request.getMethod() == HttpMethod.POST &&
                (contentType == null ||
                        MediaType.APPLICATION_JSON.equals(contentType) ||
                        MediaType.APPLICATION_JSON_UTF8.equals(contentType))) {
            return this.handlePostReq(exchange, chain);
        } else {
            return chain.filter(exchange);
        }
    }

Get請(qǐng)求參數(shù)解密包裝 ServerHttpRequestDecorator

//構(gòu)造查詢參數(shù)Map
        MultiValueMap<String, String> map = buildMultiValueMap(dataJson);
        //新的解密后的uri
        ServerHttpRequest newHttpRequest = this.buildNewServerHttpRequest(request, map);
        //新的解密后的uri request
        ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(newHttpRequest) {
            @Override
            public MultiValueMap<String, String> getQueryParams() {
                return map;
            }

        };

post請(qǐng)求參數(shù)解密包裝 ServerHttpRequestDecorator

//構(gòu)造一個(gè)請(qǐng)求包裝
        final MultiValueMap<String, String> finalQueryParamMap = new LinkedMultiValueMap<>(queryParamMap);
        ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(request) {

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                return httpHeaders;
            }

            //處理post url傳參解密
            @Override
            public MultiValueMap<String, String> getQueryParams() {
                if (queryParamsDecrypt) {
                    return finalQueryParamMap;
                }
                return super.getQueryParams();
            }

            @Override
            public Flux<DataBuffer> getBody() {
                //注意: 這里需要buffer一下,拿到完整報(bào)文后再map解密
                return super.getBody().buffer().map(buffer -> {
                    DataBuffer joinDataBuffer = dataBufferFactory.join(buffer);
                    byte[] content = new byte[joinDataBuffer.readableByteCount()];
                    joinDataBuffer.read(content);
                    DataBufferUtils.release(joinDataBuffer);
                    String decryptData = new String(content, StandardCharsets.UTF_8);
                    log.info("post decryptData: {}", decryptData);
                    if (!queryParamsDecrypt && StringUtils.isEmpty(decryptData)) {
                        throw new CryptoException("參數(shù)格式錯(cuò)誤");
                    } else {
                        JSONObject dataJsonObj = JSON.parseObject(decryptData);
                        if (!queryParamsDecrypt && !dataJsonObj.containsKey(cryptoProperties.getParamName())) {
                            throw new CryptoException("參數(shù)格式錯(cuò)誤");
                        }
                        byte[] bytes = AesUtil.decryptFormBase64(dataJsonObj.getString(cryptoProperties.getParamName()), cryptoProperties.getAesKey());
                        return dataBufferFactory.wrap(Objects.requireNonNull(bytes));
                    }
                });

GET/POST返回值加密處理CryptoServerHttpResponseDecorator

class CryptoServerHttpResponseDecorator extends ServerHttpResponseDecorator {
        final DataBufferFactory bufferFactory;
        boolean isPass = false;
        public CryptoServerHttpResponseDecorator(ServerHttpResponse delegate) {
            super(delegate);
            bufferFactory = delegate.bufferFactory();
        }

        @Override
        public HttpHeaders getHeaders() {
            HttpHeaders headers = super.getHeaders();
            //同一個(gè)請(qǐng)求此處有可能調(diào)用多次,先重置為false
            isPass = false;
            if (headers.getContentType() != null &&
                    !MediaType.APPLICATION_JSON.equals(headers.getContentType()) &&
                    !MediaType.APPLICATION_JSON_UTF8.equals(headers.getContentType())) {
                //相應(yīng)體ContentType只處理json
                isPass = true;
            } else if (!headers.containsKey(cryptoProperties.getCryptoVersionHeader())) {
                //添加version響應(yīng)頭
                headers.add(cryptoProperties.getCryptoVersionHeader(), cryptoProperties.getCryptoVersion());
            }
            return headers;
        }

        //調(diào)用 writeWith 和 writeAndFlushWith 判斷: NettyWriteResponseFilter

        // application/json;charset=UTF-8 走這里
        @Override
        public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
            if (body instanceof Flux && !isPass) {
                Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
                    DataBuffer joinDataBuffer = bufferFactory.join(dataBuffer);
                    byte[] content = new byte[joinDataBuffer.readableByteCount()];
                    joinDataBuffer.read(content);
                    DataBufferUtils.release(joinDataBuffer);
                    Map<String, String> data = new HashMap<>(1);
                    data.put(cryptoProperties.getParamName(), AesUtil.encryptToBase64(content, cryptoProperties.getAesKey()));
                    return bufferFactory.wrap(JSON.toJSONString(data).getBytes(StandardCharsets.UTF_8));
                }));
            }
            return super.writeWith(body);
        }

        // StreamingMediaType類型:application/stream 和 application/stream+json 走這里
        @Override
        public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
            return super.writeAndFlushWith(body);
        }
    }

完整CryptoFilter實(shí)現(xiàn)

package org.xx.xx.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBufAllocator;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.xx.xx.gateway.props.CryptoProperties;
import org.xx.xx.gateway.provider.RequestProvider;
import org.xx.xx.gateway.provider.ResponseProvider;
import org.xx.xx.gateway.util.AesUtil;
import org.xx.xx.gateway.util.StringPool;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * CryptoFilter
 *
 * @author lizheng 
 * @version 1.0
 * @date 2022/3/11 上午10:57
 */
@Slf4j
@RequiredArgsConstructor
@Configuration
@ConditionalOnProperty(value = "gateway.crypto.enabled", havingValue = "true", matchIfMissing = true)
public class CryptoFilter implements GlobalFilter, Ordered {

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    private final DataBufferFactory dataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);

    private final CryptoProperties cryptoProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (!cryptoProperties.isEnabled()) {
            return chain.filter(exchange);
        }
        ServerHttpRequest request = exchange.getRequest();
        //校驗(yàn)請(qǐng)求路徑跳過(guò)加密
        String originalRequestUrl = RequestProvider.getOriginalRequestUrl(exchange);
        String path = exchange.getRequest().getURI().getPath();
        if (isSkip(path) || isSkip(originalRequestUrl)) {
            return chain.filter(exchange);
        }

        HttpHeaders headers = request.getHeaders();
        MediaType contentType = headers.getContentType();

        //后期算法升級(jí)擴(kuò)展,暫時(shí)只判斷是否相等
        if (!cryptoProperties.getCryptoVersion().equals(headers.getFirst(cryptoProperties.getCryptoVersionHeader()))) {
            return Mono.error(new CryptoException("加密版本不支持"));
        }

        if (request.getMethod() == HttpMethod.GET) {
            return this.handleGetReq(exchange, chain);
        } else if (request.getMethod() == HttpMethod.POST &&
                (contentType == null ||
                        MediaType.APPLICATION_JSON.equals(contentType) ||
                        MediaType.APPLICATION_JSON_UTF8.equals(contentType))) {
            return this.handlePostReq(exchange, chain);
        } else {
            return chain.filter(exchange);
        }
    }

    class CryptoServerHttpResponseDecorator extends ServerHttpResponseDecorator {
        final DataBufferFactory bufferFactory;
        boolean isPass = false;
        public CryptoServerHttpResponseDecorator(ServerHttpResponse delegate) {
            super(delegate);
            bufferFactory = delegate.bufferFactory();
        }

        @Override
        public HttpHeaders getHeaders() {
            HttpHeaders headers = super.getHeaders();
            //同一個(gè)請(qǐng)求此處有可能調(diào)用多次,先重置為false
            isPass = false;
            if (headers.getContentType() != null &&
                    !MediaType.APPLICATION_JSON.equals(headers.getContentType()) &&
                    !MediaType.APPLICATION_JSON_UTF8.equals(headers.getContentType())) {
                //相應(yīng)體ContentType只處理json
                isPass = true;
            } else if (!headers.containsKey(cryptoProperties.getCryptoVersionHeader())) {
                //添加version響應(yīng)頭
                headers.add(cryptoProperties.getCryptoVersionHeader(), cryptoProperties.getCryptoVersion());
            }
            return headers;
        }

        //調(diào)用 writeWith 和 writeAndFlushWith 判斷: NettyWriteResponseFilter

        // application/json;charset=UTF-8 走這里
        @Override
        public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
            if (body instanceof Flux && !isPass) {
                Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
                    DataBuffer joinDataBuffer = bufferFactory.join(dataBuffer);
                    byte[] content = new byte[joinDataBuffer.readableByteCount()];
                    joinDataBuffer.read(content);
                    DataBufferUtils.release(joinDataBuffer);
                    Map<String, String> data = new HashMap<>(1);
                    data.put(cryptoProperties.getParamName(), AesUtil.encryptToBase64(content, cryptoProperties.getAesKey()));
                    return bufferFactory.wrap(JSON.toJSONString(data).getBytes(StandardCharsets.UTF_8));
                }));
            }
            return super.writeWith(body);
        }

        // StreamingMediaType類型:application/stream 和 application/stream+json 走這里
        @Override
        public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
            return super.writeAndFlushWith(body);
        }
    }

    @SneakyThrows
    private Mono<Void> handlePostReq(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String paramData = request.getQueryParams().getFirst(cryptoProperties.getParamName());
        MultiValueMap<String, String> queryParamMap = new LinkedMultiValueMap<>();
        final boolean queryParamsDecrypt = !StringUtils.isEmpty(paramData);
        if (queryParamsDecrypt) {
            String dataJson;
            try {
                //AES解密
                dataJson = AesUtil.decryptFormBase64ToString(paramData, cryptoProperties.getAesKey());
            } catch (Exception e) {
                log.error("請(qǐng)求參數(shù)解密異常: ", e);
                return cryptoError(exchange.getResponse(), "請(qǐng)求參數(shù)解密異常");
            }
            //構(gòu)造查詢參數(shù)Map
            queryParamMap = buildMultiValueMap(dataJson);
            //新的解密后的uri request
            request = this.buildNewServerHttpRequest(request, queryParamMap);
        }

        //構(gòu)造一個(gè)請(qǐng)求包裝
        final MultiValueMap<String, String> finalQueryParamMap = new LinkedMultiValueMap<>(queryParamMap);
        ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(request) {

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                return httpHeaders;
            }

            @Override
            public MultiValueMap<String, String> getQueryParams() {
                if (queryParamsDecrypt) {
                    return finalQueryParamMap;
                }
                return super.getQueryParams();
            }

            @Override
            public Flux<DataBuffer> getBody() {
                //注意: 這里需要buffer,拿到完整報(bào)文后再map解密
                return super.getBody().buffer().map(buffer -> {
                    DataBuffer joinDataBuffer = dataBufferFactory.join(buffer);
                    byte[] content = new byte[joinDataBuffer.readableByteCount()];
                    joinDataBuffer.read(content);
                    DataBufferUtils.release(joinDataBuffer);
                    String decryptData = new String(content, StandardCharsets.UTF_8);
                    log.info("post decryptData: {}", decryptData);
                    if (!queryParamsDecrypt && StringUtils.isEmpty(decryptData)) {
                        throw new CryptoException("參數(shù)格式錯(cuò)誤");
                    } else {
                        JSONObject dataJsonObj = JSON.parseObject(decryptData);
                        if (!queryParamsDecrypt && !dataJsonObj.containsKey(cryptoProperties.getParamName())) {
                            throw new CryptoException("參數(shù)格式錯(cuò)誤");
                        }
                        byte[] bytes = AesUtil.decryptFormBase64(dataJsonObj.getString(cryptoProperties.getParamName()), cryptoProperties.getAesKey());
                        return dataBufferFactory.wrap(Objects.requireNonNull(bytes));
                    }
                });
            }
        };
        return chain.filter(exchange.mutate()
                .request(decorator)
                .response(new CryptoServerHttpResponseDecorator(exchange.getResponse()))
                .build());
    }

    @SneakyThrows
    private Mono<Void> handleGetReq(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if (request.getQueryParams().isEmpty()) {
            // get無(wú)參數(shù) 不走參數(shù)解密
            return chain.filter(exchange.mutate()
                    .request(request)
                    .response(new CryptoServerHttpResponseDecorator(exchange.getResponse()))
                    .build());
        }
        String paramData = request.getQueryParams().getFirst(cryptoProperties.getParamName());

        if (StringUtils.isEmpty(paramData)) {
            //有參數(shù)但是密文字段不存在
            throw new CryptoException("參數(shù)格式錯(cuò)誤");
        }

        String dataJson;
        try {
            //AES解密
            dataJson = AesUtil.decryptFormBase64ToString(paramData, cryptoProperties.getAesKey());
        } catch (Exception e) {
            log.error("請(qǐng)求參數(shù)解密異常: ", e);
            return cryptoError(exchange.getResponse(), "請(qǐng)求參數(shù)解密異常");
        }
        //構(gòu)造查詢參數(shù)Map
        MultiValueMap<String, String> map = buildMultiValueMap(dataJson);
        //新的解密后的uri
        ServerHttpRequest newHttpRequest = this.buildNewServerHttpRequest(request, map);
        //新的解密后的uri request
        ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(newHttpRequest) {
            @Override
            public MultiValueMap<String, String> getQueryParams() {
                return map;
            }

        };
        return chain.filter(exchange.mutate()
                .request(decorator)
                .response(new CryptoServerHttpResponseDecorator(exchange.getResponse()))
                .build());
    }

    private MultiValueMap<String, String> buildMultiValueMap(String dataJson) {
        JSONObject jsonObject = JSON.parseObject(dataJson);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>(jsonObject.size());
        for (String key : jsonObject.keySet()) {
            map.put(key, Lists.newArrayList(jsonObject.getString(key)));
        }
        return map;
    }

    private ServerHttpRequest buildNewServerHttpRequest(ServerHttpRequest request, MultiValueMap<String, String> params) throws URISyntaxException {
        StringBuilder queryBuilder = new StringBuilder();
        for (String key : params.keySet()) {
            queryBuilder.append(key);
            queryBuilder.append(StringPool.EQUALS);
            queryBuilder.append(params.getFirst(key));
            queryBuilder.append(StringPool.AMPERSAND);
        }
        queryBuilder.deleteCharAt(queryBuilder.length() - 1);

        //經(jīng)過(guò)測(cè)試只覆蓋 ServerHttpRequest的getQueryParams路由分發(fā)之后,無(wú)法攜帶過(guò)去新的參數(shù),所以這里需要構(gòu)造一個(gè)新的解密后的uri
        URI uri = request.getURI();
        URI newUri = new URI(uri.getScheme(),
                uri.getUserInfo(),
                uri.getHost(),
                uri.getPort(),
                uri.getPath(),
                queryBuilder.toString(),
                uri.getFragment());

        //構(gòu)造一個(gè)新的ServerHttpRequest
        return request.mutate().uri(newUri).build();
    }

    private boolean isSkip(String path) {
        for (String pattern : cryptoProperties.getSkipPathPattern()) {
            if (antPathMatcher.match(pattern, path)) {
                return true;
            }
        }
       return false;
    }

    private Mono<Void> cryptoError(ServerHttpResponse resp, String msg) {
        resp.setStatusCode(HttpStatus.UNAUTHORIZED);
        resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        String result = JSON.toJSONString(ResponseProvider.unAuth(msg));
        DataBuffer buffer = resp.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Flux.just(buffer));
    }

    @Override
    public int getOrder() {
        return -200;
    }
}

以上就是SpringCloud Gateway實(shí)現(xiàn)API接口加解密的詳細(xì)內(nèi)容,更多關(guān)于SpringCloud Gateway接口加解密的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中的CyclicBarrier循環(huán)柵欄詳解

    Java中的CyclicBarrier循環(huán)柵欄詳解

    這篇文章主要介紹了Java中的CyclicBarrier循環(huán)柵欄詳解,CyclicBarrier循環(huán)柵欄是用來(lái)進(jìn)行線程協(xié)作,等待線程滿足某個(gè)計(jì)數(shù),構(gòu)造時(shí)設(shè)置計(jì)數(shù)個(gè)數(shù),每個(gè)線程執(zhí)行到某個(gè)需要“同步”的時(shí)刻調(diào)用 await()方法進(jìn)行等待,當(dāng)?shù)却木€程數(shù)滿足計(jì)數(shù)個(gè)數(shù)時(shí),繼續(xù)執(zhí)行,需要的朋友可以參考下
    2023-12-12
  • Mybatis批量插入大量數(shù)據(jù)的最優(yōu)方式總結(jié)

    Mybatis批量插入大量數(shù)據(jù)的最優(yōu)方式總結(jié)

    批量插入功能是我們?nèi)粘9ぷ髦斜容^常見(jiàn)的業(yè)務(wù)功能之一,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Mybatis批量插入大量數(shù)據(jù)的幾種最優(yōu)方式,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • 解決try-catch捕獲異常信息后Spring事務(wù)失效的問(wèn)題

    解決try-catch捕獲異常信息后Spring事務(wù)失效的問(wèn)題

    這篇文章主要介紹了解決try-catch捕獲異常信息后Spring事務(wù)失效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 微服務(wù)框架FEIGN使用常見(jiàn)問(wèn)題分析

    微服務(wù)框架FEIGN使用常見(jiàn)問(wèn)題分析

    這篇文章主要為大家介紹了微服務(wù)框架FEIGN常見(jiàn)問(wèn)題分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Mybatis與Jpa的區(qū)別和性能對(duì)比總結(jié)

    Mybatis與Jpa的區(qū)別和性能對(duì)比總結(jié)

    mybatis和jpa兩個(gè)持久層框架,從底層到用法都不同,但是實(shí)現(xiàn)的功能是一樣的,所以說(shuō)一直以來(lái)頗有爭(zhēng)議,所以下面這篇文章主要給大家介紹了關(guān)于Mybatis與Jpa的區(qū)別和性能對(duì)比的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • mybatis insert foreach循環(huán)插入方式

    mybatis insert foreach循環(huán)插入方式

    這篇文章主要介紹了mybatis insert foreach循環(huán)插入方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot定時(shí)監(jiān)聽RocketMQ的NameServer問(wèn)題及解決方案

    SpringBoot定時(shí)監(jiān)聽RocketMQ的NameServer問(wèn)題及解決方案

    這篇文章主要介紹了SpringBoot定時(shí)監(jiān)聽RocketMQ的NameServer問(wèn)題及解決方案,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-12-12
  • SpringMVC結(jié)合天氣api實(shí)現(xiàn)天氣查詢

    SpringMVC結(jié)合天氣api實(shí)現(xiàn)天氣查詢

    這篇文章主要為大家詳細(xì)介紹了SpringMVC結(jié)合天氣api實(shí)現(xiàn)天氣查詢,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Java代碼執(zhí)行順序——類的初始化場(chǎng)景

    Java代碼執(zhí)行順序——類的初始化場(chǎng)景

    這篇文章主要為大家介紹了Java代碼執(zhí)行順序類的初始化場(chǎng)景實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • 一起來(lái)學(xué)習(xí)Java IO的轉(zhuǎn)化流

    一起來(lái)學(xué)習(xí)Java IO的轉(zhuǎn)化流

    這篇文章主要為大家詳細(xì)介紹了Java IO的轉(zhuǎn)化流,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03

最新評(píng)論

图片| 合作市| 奉节县| 泸溪县| 沐川县| 英超| 紫云| 湖北省| 逊克县| 汝城县| 沂南县| 伽师县| 金坛市| 乡城县| 凉城县| 正镶白旗| 六枝特区| 开平市| 崇左市| 锡林郭勒盟| 拉萨市| 普安县| 奎屯市| 孟村| 克什克腾旗| 靖西县| 嘉定区| 石泉县| 米泉市| 乌鲁木齐县| 灵璧县| 阿克苏市| 苏州市| 荔波县| 峡江县| 镇赉县| 晋宁县| 肥西县| 金堂县| 微博| 康定县|