欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實現(xiàn)微信支付的項目實踐

 更新時間:2023年10月11日 16:00:37   作者:程序猿小張丶  
最近的一個項目中涉及到了支付業(yè)務(wù),其中用到了微信支付和支付寶支付,本文就來介紹一下Java實現(xiàn)微信支付的項目實踐,具有一定的參考價值,感興趣的可以了解一下

摘要:最近的一個項目中涉及到了支付業(yè)務(wù),其中用到了微信支付和支付寶支付,在做的過程中也遇到些問題,所以現(xiàn)在總結(jié)梳理一下,分享給有需要的人,也為自己以后回顧留個思路。

一、微信支付接入準(zhǔn)備工作:

首先,微信支付,只支持企業(yè)用戶,個人用戶是不能接入微信支付的,所以要想接入微信支付,首先需要有微信公眾號,這個的企業(yè)才能申請。有了微信公眾號,就能申請微信支付的相關(guān)內(nèi)容,所以在準(zhǔn)備開始寫代碼之前需要先把下面的這些參數(shù)申請好:公眾賬號ID、微信支付商戶號、API密鑰、AppSecret是APPID對應(yīng)的接口密碼、回調(diào)地址(回調(diào)必須保證外網(wǎng)能訪問到此地址)、發(fā)起請求的電腦IP

二、微信支付流程說明:

有了上面提到的這些參數(shù),那我們就可以接入微信支付了,下面我來看下微信支付的官方文檔(https://pay.weixin.qq.com/wiki/doc/api/index.html)、訪問該地址可以看到有多種支付方式可以選擇,我們這里選擇掃碼支付的方式(https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1)

這里我們選擇模式二,下面看下模式二的時序圖,如下圖:

模式二與模式一相比,流程更為簡單,不依賴設(shè)置的回調(diào)支付URL。商戶后臺系統(tǒng)先調(diào)用微信支付的統(tǒng)一下單接口,微信后臺系統(tǒng)返回鏈接參數(shù)code_url,商戶后臺系統(tǒng)將code_url值生成二維碼圖片,用戶使用微信客戶端掃碼后發(fā)起支付。注意:code_url有效期為2小時,過期后掃碼不能再發(fā)起支付。

三、微信支付所需Maven依賴

    <!--微信支付SDK-->
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.3.0</version>
        </dependency>
        <!-- json處理器:引入gson依賴 -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.12</version>
        </dependency>
        <!-- 二維碼 -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.3</version>
        </dependency>
        <!-- 生成二維碼 -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.3.3</version>
        </dependency>

四、配置文件添加微信支付所需參數(shù)

# 微信支付相關(guān)參數(shù)
wxpay:
  # 商戶號
  mch-id: xxxxxxx
  # 商戶API證書序列號
  mch-serial-no: xxxxxxxxxx
  # 商戶私鑰文件
  # 注意:該文件放在項目根目錄下
  private-key-path: ./apiclient_key.pem
  # APIv3密鑰
  api-v3-key: xxxxxxxx
  # APPID
  appid: xxxxxxc27e0e7cxxx
  # 微信服務(wù)器地址
  domain: https://api.mch.weixin.qq.com
  # 接收結(jié)果通知地址
  # 注意:每次重新啟動ngrok,都需要根據(jù)實際情況修改這個配置
  notify-domain: https://c7c1-240e-3b5-3015-be0-1bc-9bed-fca4-d09b.ngrok.io

五、微信支付下單代碼實現(xiàn)

1.Controller層

 /**
     * native下單
     */
    @ApiOperation(value = "native 微信支付下單 返回Image")
    @GetMapping("/native")
    public BaseRes<String> nativePay(@RequestParam("packageId") Integer packageId) {
        return wxPayService.nativePay(packageId);
    }
  /**
     * JSAPI下單
     */
    @ApiOperation(value = "JSAPI微信支付下單")
    @GetMapping("/jsapi")
    public BaseRes<String> jsapiPay(@RequestParam("packageId") Integer packageId,@RequestParam("openId") String openId) {
        return wxPayService.jsapiPay(packageId,openId);
    }

注意:packageId是套餐Id,可根據(jù)情況修改

2.Service層

   BaseRes<String> nativePay(Integer packageId);
   BaseRes<String> jsapiPay(Integer packageId, String openId);

3.實現(xiàn)層

   /**
     * Mavicat下單
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    @SneakyThrows
    public BaseRes<String> nativePay(Integer packageId){
        log.info("發(fā)起Navicat支付請求");
        HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.NATIVE_PAY.getType()));
        CloseableHttpResponse response = wxPayExecute(packageId, null, httpPost);
        try {
            String bodyAsString = EntityUtils.toString(response.getEntity());//響應(yīng)體
            int statusCode = response.getStatusLine().getStatusCode();//響應(yīng)狀態(tài)碼
            if (statusCode == 200) { //處理成功
                log.info("成功, 返回結(jié)果 = " + bodyAsString);
            } else if (statusCode == 204) { //處理成功,無返回Body
                log.info("成功");
            } else {
                log.info("Native下單失敗,響應(yīng)碼 = " + statusCode + ",返回結(jié)果 = " + bodyAsString);
                throw new IOException("request failed");
            }
            Gson gson = new Gson();
            //響應(yīng)結(jié)果
            Map<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
            //二維碼
            String codeUrl = resultMap.get("code_url");
            return new BaseRes<>(codeUrl,ServiceCode.SUCCESS);
            //生成二維碼
//            WxPayUtil.makeQRCode(codeUrl);
        } finally {
            response.close();
        }
    }
  /**
     * JSAPI下單
     * @return
     */
    @Override
    @SneakyThrows
    public BaseRes<String> jsapiPay(Integer packageId, String openId) {
        log.info("發(fā)起Navicat支付請求");
        HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.JSAPI_PAY.getType()));
        CloseableHttpResponse response = wxPayExecute(packageId, openId, httpPost);
        try {
            String bodyAsString = EntityUtils.toString(response.getEntity());//響應(yīng)體
            int statusCode = response.getStatusLine().getStatusCode();//響應(yīng)狀態(tài)碼
            if (statusCode == 200) { //處理成功
                log.info("成功, 返回結(jié)果 = " + bodyAsString);
            } else if (statusCode == 204) { //處理成功,無返回Body
                log.info("成功");
            } else {
                log.info("JSAPI下單失敗,響應(yīng)碼 = " + statusCode + ",返回結(jié)果 = " + bodyAsString);
                throw new IOException("request failed");
            }
            Gson gson = new Gson();
            //響應(yīng)結(jié)果
            Map<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
            String prepayId = resultMap.get("prepay_id");
            return new BaseRes<>(prepayId,ServiceCode.SUCCESS);
        } finally {
            response.close();
        }
    }
 // 封裝統(tǒng)一下單方法	
  private CloseableHttpResponse wxPayExecute(Integer packageId,String openId,HttpPost httpPost) throws IOException {
        // 獲取套餐金額 還有相關(guān)信息
        ChatPackage chatPackage = chatPackageMapper.selectById(packageId);
        if (null == chatPackage) {
            throw new NingException(ServiceCode.FAILED);
        }
        BigDecimal amount = chatPackage.getAmount();
        if (null == amount || amount.equals(BigDecimal.ZERO)) {
            throw new NingException(ServiceCode.SUCCESS);
        }
		// 從登錄信息中獲取用戶信息
        TokenUser loginUserInfo = CommUtils.getLoginUserInfo();
        Integer userId = loginUserInfo.getUserId();
        // 請求body參數(shù)
        Gson gson = new Gson();
        Map<String,Object> paramsMap = new HashMap<>();
        paramsMap.put("appid", wxPayConfig.getAppid());
        paramsMap.put("mchid", wxPayConfig.getMchId());
        paramsMap.put("description", chatPackage.getName());
        paramsMap.put("out_trade_no", WxPayUtil.generateOrderNumber(userId,packageId)); //訂單號
        paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxApiType.NATIVE_NOTIFY.getType()));
        Map<String,Object> amountMap = new HashMap<>();
        //由單位:元 轉(zhuǎn)換為單位:分,并由Bigdecimal轉(zhuǎn)換為整型
        BigDecimal total = amount.multiply(new BigDecimal(100));
        amountMap.put("total", total.intValue());
        amountMap.put("currency", "CNY");
        paramsMap.put("amount", amountMap);
		// 判斷是Navicat下單還是JSAPI下單 JSAPI需要傳OPENID
        if (StringUtils.isNotBlank(openId)) {
            Map<String,Object> payerMap = new HashMap<>();
            payerMap.put("openid",openId);
            paramsMap.put("payer",payerMap);
        }
        JSONObject attachJson = new JSONObject();
        attachJson.put("packageId",packageId);
        attachJson.put("userId",userId);
        attachJson.put("total",total);
        paramsMap.put("attach",attachJson.toJSONString());
        //將參數(shù)轉(zhuǎn)換成json字符串
        String jsonParams = gson.toJson(paramsMap);
        log.info("請求參數(shù) ===> {}" , jsonParams);
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        //完成簽名并執(zhí)行請求
        return wxPayClient.execute(httpPost);
    }

六、微信支付回調(diào)接口

1.Controller層

   /**
     * 支付通知
     * 微信支付通過支付通知接口將用戶支付成功消息通知給商戶
     */
    @ApiOperation(value = "支付通知", notes = "支付通知")
    @PostMapping("/pay/notify")
    @ClientAuthControl
    public WxRes nativeNotify() {
        return wxPayService.nativeNotify();
    }

2.Service層

WxRes nativeNotify();

3.實現(xiàn)層

@Resource
    private Verifier verifier;
    private final ReentrantLock lock = new ReentrantLock();
    @Override
    @SneakyThrows
    @Transactional
    public WxRes nativeNotify() {
        HttpServletRequest request = CommUtils.getRequest();
        HttpServletResponse response = CommUtils.getResponse();
        Gson gson = new Gson();
        try {
            //處理通知參數(shù)
            String body = WxPayUtil.readData(request);
            Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
            String requestId = (String) bodyMap.get("id");
            //簽名的驗證
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
                    = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if (wechatPay2ValidatorForRequest.validate(request)) {
                throw new RuntimeException();
            }
            log.info("通知驗簽成功");
            //處理訂單
            processOrder(bodyMap);
            return new WxRes("SUCCESS","成功");
        } catch (Exception e) {
            e.printStackTrace();
            response.setStatus(500);
            return new WxRes("FAIL","成功");
        }
    }
   /**
     * 處理訂單
     *
     * @param bodyMap
     */
    @Transactional
    @SneakyThrows
    public void processOrder(Map<String, Object> bodyMap){
        log.info("處理訂單");
        //解密報文
        String plainText = decryptFromResource(bodyMap);
        //將明文轉(zhuǎn)換成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText, HashMap.class);
        String orderNo = (String) plainTextMap.get("out_trade_no");
        String attach = (String) plainTextMap.get("attach");
        JSONObject attachJson = JSONObject.parseObject(attach);
        Integer packageId = attachJson.getInteger("packageId");
        Integer userId = attachJson.getInteger("userId");
        Integer total = attachJson.getInteger("total");
        /*在對業(yè)務(wù)數(shù)據(jù)進(jìn)行狀態(tài)檢查和處理之前,
        要采用數(shù)據(jù)鎖進(jìn)行并發(fā)控制,
        以避免函數(shù)重入造成的數(shù)據(jù)混亂*/
        //嘗試獲取鎖:
        // 成功獲取則立即返回true,獲取失敗則立即返回false。不必一直等待鎖的釋放
        if (lock.tryLock()) {
            try {
                log.info("plainText={}",plainText);
                //處理重復(fù)的通知
                //接口調(diào)用的冪等性:無論接口被調(diào)用多少次,產(chǎn)生的結(jié)果是一致的。
                String orderStatus = orderService.getOrderStatus(orderNo);
                if (!OrderStatus.NOTPAY.getType().equals(orderStatus)) {
                    return;
                }
				// TODO 修改訂單狀態(tài)、添加支付記錄等
                // 通知前端用戶 已完成支付
                messageSocketHandle.sendMessageByUserID(userId,new TextMessage("PaySuccess"));
            } finally {
                //要主動釋放鎖
                lock.unlock();
            }
        }
    }
	/**
     * 對稱解密
     *
     * @param bodyMap
     * @return
     */
    @SneakyThrows
    private String decryptFromResource(Map<String, Object> bodyMap) {
        log.info("密文解密");
        //通知數(shù)據(jù)
        Map<String, String> resourceMap = (Map) bodyMap.get("resource");
        //數(shù)據(jù)密文
        String ciphertext = resourceMap.get("ciphertext");
        //隨機(jī)串
        String nonce = resourceMap.get("nonce");
        //附加數(shù)據(jù)
        String associatedData = resourceMap.get("associated_data");
        AesUtil aesUtil = new AesUtil(wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        //數(shù)據(jù)明文
        String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                ciphertext);
        return plainText;
    }

七、工具類和相關(guān)配置類

1.WxPayUtil工具類

@Slf4j
public class WxPayUtil {
    private static final Random random = new Random();
	// 生成訂單號
    public static String generateOrderNumber(int userId, int packageId) {
        // 獲取當(dāng)前時間戳
        long timestamp = System.currentTimeMillis();
        // 生成6位隨機(jī)數(shù)
        int randomNum = random.nextInt(900000) + 100000;
        // 組裝訂單號
        return String.format("%d%d%d%d", timestamp, randomNum, userId, packageId);
    }
    /**
     * 生成二維碼
     * @param url
     */
    public static void makeQRCode(String url){
        HttpServletResponse response = CommUtils.getResponse();
        //通過支付鏈接生成二維碼
        HashMap<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        hints.put(EncodeHintType.MARGIN, 2);
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 200, 200, hints);
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream());
            System.out.println("創(chuàng)建二維碼完成");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 將通知參數(shù)轉(zhuǎn)化為字符串
     *
     * @param request
     * @return
     */
    public static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.微信支付配置類

@Configuration
@ConfigurationProperties(prefix = "wxpay") //讀取wxpay節(jié)點
@Data //使用set方法將wxpay節(jié)點中的值填充到當(dāng)前類的屬性中
@Slf4j
public class WxPayConfig {
    // 商戶號
    private String mchId;
    // 商戶API證書序列號
    private String mchSerialNo;
    // 商戶私鑰文件
    private String privateKeyPath;
    // APIv3密鑰
    private String apiV3Key;
    // APPID
    private String appid;
    // 微信服務(wù)器地址
    private String domain;
    // 接收結(jié)果通知地址
    private String notifyDomain;
    /**
     * 獲取商戶的私鑰文件
     *
     * @param filename
     * @return
     */
    private PrivateKey getPrivateKey(String filename) {
        try {
            return PemUtil.loadPrivateKey(new FileInputStream(filename));
        } catch (FileNotFoundException e) {
            throw new RuntimeException("私鑰文件不存在", e);
        }
    }
    /**
     * 獲取簽名驗證器
     *
     * @return
     */
    @Bean
    public ScheduledUpdateCertificatesVerifier getVerifier() {
        log.info("獲取簽名驗證器");
        //獲取商戶私鑰
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
        //私鑰簽名對象
        PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, privateKey);
        //身份認(rèn)證對象
        WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);
        // 使用定時更新的簽名驗證器,不需要傳入證書
        ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
                wechatPay2Credentials,
                apiV3Key.getBytes(StandardCharsets.UTF_8));
        return verifier;
    }
    /**
     * 獲取http請求對象
     *
     * @param verifier
     * @return
     */
    @Bean(name = "wxPayClient")
    public CloseableHttpClient getWxPayClient(ScheduledUpdateCertificatesVerifier verifier) {
        log.info("獲取httpClient");
        //獲取商戶私鑰
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, mchSerialNo, privateKey)
                .withValidator(new WechatPay2Validator(verifier));
        // ... 接下來,你仍然可以通過builder設(shè)置各種參數(shù),來配置你的HttpClient
        // 通過WechatPayHttpClientBuilder構(gòu)造的HttpClient,會自動的處理簽名和驗簽,并進(jìn)行證書自動更新
        CloseableHttpClient httpClient = builder.build();
        return httpClient;
    }
    /**
     * 獲取HttpClient,無需進(jìn)行應(yīng)答簽名驗證,跳過驗簽的流程
     */
    @Bean(name = "wxPayNoSignClient")
    public CloseableHttpClient getWxPayNoSignClient() {
        //獲取商戶私鑰
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
        //用于構(gòu)造HttpClient
        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                //設(shè)置商戶信息
                .withMerchant(mchId, mchSerialNo, privateKey)
                //無需進(jìn)行簽名驗證、通過withValidator((response) -> true)實現(xiàn)
                .withValidator((response) -> true);
        // 通過WechatPayHttpClientBuilder構(gòu)造的HttpClient,會自動的處理簽名和驗簽,并進(jìn)行證書自動更新
        CloseableHttpClient httpClient = builder.build();
        log.info("== getWxPayNoSignClient END ==");
        return httpClient;
    }
}

3.微信支付枚舉類

@AllArgsConstructor
@Getter
public enum WxApiType {
    /**
     * Native下單
     */
    NATIVE_PAY("/v3/pay/transactions/native"),
    /**
     * JSAPI下單
     */
    JSAPI_PAY("/v3/pay/transactions/jsapi"),
    /**
     * 查詢訂單
     */
    ORDER_QUERY_BY_NO("/v3/pay/transactions/out-trade-no/%s"),
    /**
     * 關(guān)閉訂單
     */
    CLOSE_ORDER_BY_NO("/v3/pay/transactions/out-trade-no/%s/close"),
    /**
     * 支付通知
     */
    NATIVE_NOTIFY("/client/order/pay/notify");
    /**
     * 類型
     */
    private final String type;
}

4.簽名驗證類

@Slf4j
public class WechatPay2ValidatorForRequest {
    /**
     * 應(yīng)答超時時間,單位為分鐘
     */
    protected static final long RESPONSE_EXPIRED_MINUTES = 5;
    protected final Verifier verifier;
    protected final String requestId;
    protected final String body;
    public WechatPay2ValidatorForRequest(Verifier verifier, String requestId, String body) {
        this.verifier = verifier;
        this.requestId = requestId;
        this.body = body;
    }
    protected static IllegalArgumentException parameterError(String message, Object... args) {
        message = String.format(message, args);
        return new IllegalArgumentException("parameter error: " + message);
    }
    protected static IllegalArgumentException verifyFail(String message, Object... args) {
        message = String.format(message, args);
        return new IllegalArgumentException("signature verify fail: " + message);
    }
    public final boolean validate(HttpServletRequest request) throws IOException {
        try {
            //處理請求參數(shù)
            validateParameters(request);
            //構(gòu)造驗簽名串
            String message = buildMessage(request);
            String serial = request.getHeader(WECHAT_PAY_SERIAL);
            String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
            //驗簽
            if (!verifier.verify(serial, message.getBytes(StandardCharsets.UTF_8), signature)) {
                throw verifyFail("serial=[%s] message=[%s] sign=[%s], request-id=[%s]",
                        serial, message, signature, requestId);
            }
        } catch (IllegalArgumentException e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }
    protected final void validateParameters(HttpServletRequest request) {
        // NOTE: ensure HEADER_WECHAT_PAY_TIMESTAMP at last
        String[] headers = {WECHAT_PAY_SERIAL, WECHAT_PAY_SIGNATURE, WECHAT_PAY_NONCE, WECHAT_PAY_TIMESTAMP};
        String header = null;
        for (String headerName : headers) {
            header = request.getHeader(headerName);
            if (header == null) {
                throw parameterError("empty [%s], request-id=[%s]", headerName, requestId);
            }
        }
        //判斷請求是否過期
        String timestampStr = header;
        try {
            Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestampStr));
            // 拒絕過期請求
            if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= RESPONSE_EXPIRED_MINUTES) {
                throw parameterError("timestamp=[%s] expires, request-id=[%s]", timestampStr, requestId);
            }
        } catch (DateTimeException | NumberFormatException e) {
            throw parameterError("invalid timestamp=[%s], request-id=[%s]", timestampStr, requestId);
        }
    }
    protected final String buildMessage(HttpServletRequest request) throws IOException {
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        return timestamp + "\n"
                + nonce + "\n"
                + body + "\n";
    }
    protected final String getResponseBody(CloseableHttpResponse response) throws IOException {
        HttpEntity entity = response.getEntity();
        return (entity != null && entity.isRepeatable()) ? EntityUtils.toString(entity) : "";
    }
}

到此這篇關(guān)于Java 實現(xiàn)微信支付的項目實踐的文章就介紹到這了,更多相關(guān)Java 微信支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java如何跳出當(dāng)前的多重嵌套循環(huán)的問題

    Java如何跳出當(dāng)前的多重嵌套循環(huán)的問題

    Java中的循環(huán)結(jié)構(gòu)包括for循環(huán)、while循環(huán)、do-while循環(huán)和增強(qiáng)型for循環(huán),每種循環(huán)都有其適用場景,在循環(huán)中,break、continue和return分別用于跳出循環(huán)、跳過當(dāng)前循環(huán)和結(jié)束當(dāng)前方法,對于多重嵌套循環(huán)
    2025-01-01
  • SpringBoot結(jié)合Mybatis實現(xiàn)創(chuàng)建數(shù)據(jù)庫表的方法

    SpringBoot結(jié)合Mybatis實現(xiàn)創(chuàng)建數(shù)據(jù)庫表的方法

    本文主要介紹了SpringBoot結(jié)合Mybatis實現(xiàn)創(chuàng)建數(shù)據(jù)庫表的方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 利用Java反射機(jī)制實現(xiàn)對象相同字段的復(fù)制操作

    利用Java反射機(jī)制實現(xiàn)對象相同字段的復(fù)制操作

    這篇文章主要介紹了利用Java反射機(jī)制實現(xiàn)對象相同字段的復(fù)制操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • mybatis中如何用tinyint保存Boolean類型

    mybatis中如何用tinyint保存Boolean類型

    這篇文章主要介紹了mybatis中如何用tinyint保存Boolean類型,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 淺談Java中是否直接可以使用enum進(jìn)行傳輸

    淺談Java中是否直接可以使用enum進(jìn)行傳輸

    這篇文章主要介紹了淺談Java中是否直接可以使用enum進(jìn)行傳輸,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Springboot如何實現(xiàn)自定義異常數(shù)據(jù)

    Springboot如何實現(xiàn)自定義異常數(shù)據(jù)

    這篇文章主要介紹了Springboot如何實現(xiàn)自定義異常數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • SpringCloud-Hystrix實現(xiàn)原理總結(jié)

    SpringCloud-Hystrix實現(xiàn)原理總結(jié)

    通過hystrix可以解決雪崩效應(yīng)問題,它提供了資源隔離、降級機(jī)制、融斷、緩存等功能。接下來通過本文給大家分享SpringCloud-Hystrix實現(xiàn)原理,感興趣的朋友一起看看吧
    2021-05-05
  • SpringBoot接口正確接收時間參數(shù)的幾種方式

    SpringBoot接口正確接收時間參數(shù)的幾種方式

    這篇文章主要給大家介紹了關(guān)于SpringBoot接口正確接收時間參數(shù)的相關(guān)資料,文中通過代碼示例介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用springboot具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • 詳解使用Spring Security OAuth 實現(xiàn)OAuth 2.0 授權(quán)

    詳解使用Spring Security OAuth 實現(xiàn)OAuth 2.0 授權(quán)

    本篇文章主要介紹了詳解使用Spring Security OAuth 實現(xiàn)OAuth 2.0 授權(quán),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java中instanceof關(guān)鍵字實例講解

    Java中instanceof關(guān)鍵字實例講解

    大家好,本篇文章主要講的是Java中instanceof關(guān)鍵字實例講解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01

最新評論