支付寶對接 -- JAVA版

應(yīng)用配置

  • 登錄支付寶平臺货徙,簽約需要的服務(wù)
  • 切換到開放平臺褂删,創(chuàng)建應(yīng)用并審核上線


    image.png

支付配置

獲取方式已在字段注釋中

package org.weapon.core.pay.alipay.config;

import lombok.Data;

import java.io.Serializable;

/**
 * 支付配置信息
 *
 * @author lieber
 */
@Data
public class AliPayConfig implements Serializable {

    /**
     * 設(shè)置應(yīng)用Id类腮,創(chuàng)建應(yīng)用時支付寶提供鉴裹,后續(xù)可查看
     */
    private String appId;

    /**
     * 設(shè)置應(yīng)用私鑰,設(shè)置“接口加簽方式”時設(shè)置的立膛,后續(xù)不能查看晨汹,設(shè)置時牢記终议,文件名為:域名_私鑰.txt虫埂, 非->應(yīng)用私鑰2048.txt
     */
    private String privateKey;

    /**
     * 應(yīng)用公鑰證書內(nèi)容 appCertPublicKey_xxx.cert
     */
    private String appCertContent;

    /**
     * 支付寶公鑰證書內(nèi)容 -- alipayCertPublicKey_RSA2.cert
     */
    private String aliPayCertContent;

    /**
     * 支付寶根證書內(nèi)容  alipayRootCert.cert
     */
    private String aliPayRootCertContent;

    /**
     * 可直接從證書中獲取
     */
    private String publicKey;

}

各個方式的支付及查詢處理

引入支付寶SDK

        <!-- 支付寶sdk -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.10.97.ALL</version>
        </dependency>
         <!-- 二維碼sdk -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.1.0</version>
        </dependency>

通用實體

  • 下單結(jié)果祥山,喚起支付參數(shù)
package org.weapon.core.pay.center.ali;

import lombok.Builder;
import lombok.Data;

/**
 * @author lieber
 */
@Data
@Builder
public class OrderResult {

    private String body;

}
  • 下單參數(shù)
package org.weapon.core.pay.center.ali;

import lombok.Data;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;

/**
 * @author lieber
 */
@Data
public class PayParam {

    /** 商品標(biāo)題/交易標(biāo)題/訂單標(biāo)題/訂單關(guān)鍵字 */
    @NotBlank(message = "subject不能為空")
    private String subject;

    /** 外部訂單號 */
    @NotBlank(message = "系統(tǒng)訂單號不能為空")
    private String outTradeNo;

    /** 支付總金額,單位分 */
    @Min(0)
    @Max(Integer.MAX_VALUE)
    private Integer totalAmount;

    /** 用戶付款中途退出返回商戶網(wǎng)站的地址 */
    private String quitUrl;

    /** 原樣返回字符 */
    private String addition;

    /** 商品描述,不必填 */
    private String body;

    /** 通知地址 */
    @NotBlank(message = "通知地址不能為空")
    private String notifyUrl;

    @NotBlank(message = "回跳地址不能為空")
    private String redirectUrl;

    /** 支付者 */
    private String payerIp;

    private Integer timeoutExpress;

}
  • 退款參數(shù)
package org.weapon.core.pay.center.ali;

import lombok.Data;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;

/**
 * @author lieber
 */
@Data
public class RefundParam {

    /**
     * 商戶訂單號
     */
    @NotBlank(message = "原訂單號不能為空")
    private String outTradeNo;

    /**
     * 商戶退款單號
     */
    @NotBlank(message = "退款訂單號不能為空")
    private String outRefundNo;

    /**
     * 退款金額
     */
    @Min(0)
    @Max(Integer.MAX_VALUE)
    private int refund;

    /**
     * 原訂單總額
     */
    @Min(0)
    @Max(Integer.MAX_VALUE)
    private int total;

    /**
     * 退款原因掉伏;非必傳
     */
    private String reason;

    @NotBlank(message = "通知地址不能為空")
    private String notifyUrl;

}

  • 退款查詢參數(shù)
package org.weapon.core.pay.center.ali;

import lombok.Data;

import javax.validation.constraints.NotBlank;
import java.io.Serializable;

/**
 * @author lieber
 */
@Data
public class RefundQueryParam implements Serializable {

    /**
     * 原訂單外部交易訂單號
     */
    @NotBlank(message = "原訂單號不能為空")
    private String outTradeNo;

    /**
     * 退款外部交易訂單號
     */
    @NotBlank(message = "退款訂單號不能為空")
    private String outRefundNo;

}

工具類

  • 生成二維碼
package org.weapon.core.pay.center.ali;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Hashtable;
import java.util.Map;


@Slf4j
public class QrCodeUtil {

    private static final int BLACK = 0xFF000000;

    private static final int WHITE = 0xFFFFFFFF;

    private static String toBufferedImage(BitMatrix matrix) throws IOException {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ImageIO.write(image, "png", stream);
        return Base64.getEncoder().encodeToString(stream.toByteArray());
    }

    /**
     * 將內(nèi)容contents生成長寬均為width的圖片
     */
    public static String getQrCodeImage(String contents, int width) {
        return getQrCodeImage(contents, width, width);
    }

    /**
     * 將內(nèi)容contents生成長為width缝呕,寬為width的圖片
     */
    public static String getQrCodeImage(String contents, int width, int height) {
        try {
            Map<EncodeHintType, Object> hints = new Hashtable<>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            hints.put(EncodeHintType.CHARACTER_SET, "UTF8");

            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);

            return toBufferedImage(bitMatrix);

        } catch (Exception e) {
            log.error("create QR code error!", e);
            return null;
        }
    }
}

  • 獲取支付配置,可使用配置文件斧散、數(shù)據(jù)庫等
package org.weapon.core.pay.center.ali;

/**
 * @author lieber
 */
public interface IAliPayConfigService {

    /**
     * 獲取支付寶支付配置
     *
     * @return 配置
     */
    AliPayConfig getConfig();



}

支付寶支付及相關(guān)處理對接

package org.weapon.core.pay.center.ali;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lieber
 */
@Slf4j
public class AliPay {

    private final static String SERVER_URL = "https://openapi.alipay.com/gateway.do";

    private final static String SIGN_TYPE = "RSA2";

    private final static String FORMAT = "json";

    private final BigDecimal ONE_HUNDRED = new BigDecimal(100);

    private IAliPayConfigService configService;

    public AliPay(IAliPayConfigService configService) {
        this.configService = configService;
    }

    private AlipayClient client = null;

    /**
     * 掃碼支付
     *
     * @param payParam 支付參數(shù)
     * @return 結(jié)果
     * @throws AlipayApiException 支付寶調(diào)用異常
     */
    public OrderResult callNative(PayParam payParam) throws AlipayApiException {
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setBody(payParam.getBody());
        model.setSubject(payParam.getSubject());
        model.setOutTradeNo(payParam.getOutTradeNo());
        String timeoutExpress = this.timeoutExpress(payParam.getTimeoutExpress());
        model.setTimeoutExpress(timeoutExpress);
        model.setQrCodeTimeoutExpress(timeoutExpress);
        model.setTotalAmount(new BigDecimal(payParam.getTotalAmount()).divide(ONE_HUNDRED, 2, BigDecimal.ROUND_DOWN).toPlainString());
        model.setProductCode("FACE_TO_FACE_PAYMENT");
        request.setBizModel(model);
        request.setNotifyUrl(payParam.getNotifyUrl());
        //這里和普通的接口調(diào)用不同供常,使用的是sdkExecute
        AlipayTradePrecreateResponse response = this.getClient().sdkExecute(request);
        return OrderResult.builder().body(QrCodeUtil.getQrCodeImage(response.getQrCode(), 400)).build();

    }

    /**
     * APP支付
     *
     * @param payParam 支付參數(shù)
     * @return 結(jié)果
     * @throws AlipayApiException 支付寶調(diào)用異常
     */
    public OrderResult callApp(PayParam payParam) throws AlipayApiException {
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        if (payParam.getAddition() != null) {
            try {
                model.setPassbackParams(URLEncoder.encode(payParam.getAddition(), StandardCharsets.UTF_8.name()));
            } catch (UnsupportedEncodingException e) {
                log.error("加密參數(shù)出現(xiàn)異常:{} exception: ", payParam.getAddition(), e);
            }
        }
        model.setBody(payParam.getBody());
        model.setSubject(payParam.getSubject());
        model.setOutTradeNo(payParam.getOutTradeNo());
        model.setTimeoutExpress(this.timeoutExpress(payParam.getTimeoutExpress()));
        model.setTotalAmount(new BigDecimal(payParam.getTotalAmount()).divide(ONE_HUNDRED, 2, BigDecimal.ROUND_DOWN).toPlainString());
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(payParam.getNotifyUrl());
        request.setReturnUrl(payParam.getRedirectUrl());
        //這里和普通的接口調(diào)用不同,使用的是sdkExecute
        AlipayTradeAppPayResponse response = this.getClient().sdkExecute(request);
        return OrderResult.builder().body(response.getBody()).build();

    }

    /**
     * H5支付
     *
     * @param payParam 支付參數(shù)
     * @return 結(jié)果
     * @throws AlipayApiException 支付寶調(diào)用異常
     */
    public OrderResult callH5(PayParam payParam) throws AlipayApiException {
        AlipayTradeWapPayModel wapPayModel = new AlipayTradeWapPayModel();
        if (payParam.getAddition() != null) {
            try {
                wapPayModel.setPassbackParams(URLEncoder.encode(payParam.getAddition(), StandardCharsets.UTF_8.name()));
            } catch (UnsupportedEncodingException e) {
                log.error("加密參數(shù)出現(xiàn)異常:{} exception: ", payParam.getAddition(), e);
            }
        }
        wapPayModel.setOutTradeNo(payParam.getOutTradeNo());
        wapPayModel.setSubject(payParam.getSubject());
        wapPayModel.setTotalAmount(new BigDecimal(payParam.getTotalAmount()).divide(ONE_HUNDRED, 2, BigDecimal.ROUND_DOWN).toPlainString());
        wapPayModel.setBody(payParam.getBody());
        wapPayModel.setTimeoutExpress(this.timeoutExpress(payParam.getTimeoutExpress()));
        wapPayModel.setProductCode("QUICK_WAP_WAY");
        if (null != payParam.getQuitUrl()) {
            wapPayModel.setQuitUrl(payParam.getQuitUrl());
        }
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
        request.setBizModel(wapPayModel);
        request.setNotifyUrl(payParam.getNotifyUrl());
        request.setReturnUrl(payParam.getRedirectUrl());
        AlipayTradeWapPayResponse response = this.getClient().pageExecute(request, "GET");
        return OrderResult.builder().body(response.getBody()).build();

    }


    /**
     * PC支付
     *
     * @param payParam 支付參數(shù)
     * @return 結(jié)果
     * @throws AlipayApiException 支付寶調(diào)用異常
     */
    public OrderResult callPc(PayParam payParam) throws AlipayApiException {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        if (payParam.getAddition() != null) {
            try {
                model.setPassbackParams(URLEncoder.encode(payParam.getAddition(), StandardCharsets.UTF_8.name()));
            } catch (UnsupportedEncodingException e) {
                log.error("加密參數(shù)出現(xiàn)異常:{} exception: ", payParam.getAddition(), e);
            }
        }
        model.setBody(payParam.getBody());
        model.setSubject(payParam.getSubject());
        model.setOutTradeNo(payParam.getOutTradeNo());
        model.setTimeoutExpress(this.timeoutExpress(payParam.getTimeoutExpress()));
        model.setTotalAmount(new BigDecimal(payParam.getTotalAmount()).divide(ONE_HUNDRED, 2, BigDecimal.ROUND_DOWN).toPlainString());
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(payParam.getNotifyUrl());
        request.setReturnUrl(payParam.getRedirectUrl());
        AlipayTradePagePayResponse response = this.getClient().pageExecute(request);
        return OrderResult.builder().body(response.getBody()).build();

    }

    /**
     * 訂單查詢
     *
     * @param outTradeNo 訂單號
     * @return 訂單信息
     * @throws AlipayApiException 支付寶調(diào)用異常
     */
    public AlipayTradeQueryResponse query(String outTradeNo) throws AlipayApiException {
        AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
        queryRequest.setBizModel(model);
        AlipayTradeQueryResponse response = this.getClient().certificateExecute(queryRequest);
        return response;

    }

    /**
     * 退款
     *
     * @param refundParam 退款參數(shù)
     * @return 退款響應(yīng)
     * @throws AlipayApiException 支付寶調(diào)用異常
     */
    public AlipayTradeRefundResponse refund(RefundParam refundParam) throws AlipayApiException {
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setOutTradeNo(refundParam.getOutTradeNo());
        model.setOutRequestNo(refundParam.getOutRefundNo());
        model.setRefundReason(refundParam.getReason());
        model.setRefundAmount(new BigDecimal(refundParam.getRefund()).divide(ONE_HUNDRED, 2, BigDecimal.ROUND_DOWN).toPlainString());

        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        request.setBizModel(model);
        request.setNotifyUrl(refundParam.getNotifyUrl());

        AlipayTradeRefundResponse response = this.getClient().certificateExecute(request);
        return response;

    }

    /**
     * 退款查詢
     *
     * @param refundQueryParam 退款查詢參數(shù)
     * @return 退款單信息
     * @throws AlipayApiException 支付寶調(diào)用異常
     */
    public AlipayTradeFastpayRefundQueryResponse queryRefund(RefundQueryParam refundQueryParam) throws AlipayApiException {
        AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
        AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
        model.setOutTradeNo(refundQueryParam.getOutTradeNo());
        model.setOutRequestNo(refundQueryParam.getOutRefundNo());
        request.setBizModel(model);

        AlipayTradeFastpayRefundQueryResponse response = this.getClient().certificateExecute(request);
        return response;

    }

    /**
     * 支付結(jié)果通知處理
     *
     * @param request 請求
     * @return 處理成功時返回數(shù)據(jù)信息鸡捐,否則返回空
     */
    public Map<String, String> payNotify(HttpServletRequest request) {
        Map<String, String> body = this.getRequestBody(request);
        boolean flag = this.verifySign(body);
        log.info("驗簽結(jié)果為:{}", flag);
        if (!flag) {
            return null;
        }
        return body;
    }

    /**
     * 支付寶通知響應(yīng)
     *
     * @param success 是否處理成功
     * @return 響應(yīng)字符串
     */
    public String response(boolean success) {
        return success ? "success" : "fail";
    }

    private boolean verifySign(Map<String, String> notifyParam) {
        AliPayConfig config = this.configService.getConfig();
        String signType = notifyParam.get("sign_type");
        boolean flag = false;
        try {
            flag = AlipaySignature.rsaCheckV1(notifyParam, config.getPublicKey(), StandardCharsets.UTF_8.name(), signType);
        } catch (AlipayApiException e) {
            log.error("驗證簽名出現(xiàn)異常:{} {}", e, notifyParam);
        }
        return flag;
    }

    private Map<String, String> getRequestBody(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>(10);
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            StringBuilder stringBuilder = new StringBuilder();
            for (String val : values) {
                stringBuilder.append(val).append(",");
            }
            params.put(name, stringBuilder.substring(0, stringBuilder.length() - 1));
        }
        return params;
    }

    private AlipayClient getClient() {
        if (client == null) {
            client = buildClient();
            if (client == null) {
                throw new IllegalArgumentException("參數(shù)錯誤");
            }
        }
        return client;
    }

    private AlipayClient buildClient() {
        AliPayConfig config = configService.getConfig();
        if (config == null) {
            return null;
        }
        // 構(gòu)造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        // 設(shè)置網(wǎng)關(guān)地址
        certAlipayRequest.setServerUrl(SERVER_URL);
        // 設(shè)置應(yīng)用Id
        certAlipayRequest.setAppId(config.getAppId());
        // 設(shè)置應(yīng)用私鑰
        certAlipayRequest.setPrivateKey(config.getPrivateKey());
        // 設(shè)置請求格式栈暇,固定值json
        certAlipayRequest.setFormat(FORMAT);
        // 設(shè)置字符集
        certAlipayRequest.setCharset(StandardCharsets.UTF_8.name());
        // 設(shè)置簽名類型
        certAlipayRequest.setSignType(SIGN_TYPE);
        // 設(shè)置應(yīng)用公鑰證書路徑
        certAlipayRequest.setCertContent(config.getAppCertContent());
        // 設(shè)置支付寶公鑰證書路徑
        certAlipayRequest.setAlipayPublicCertContent(config.getAliPayCertContent());
        // 設(shè)置支付寶根證書路徑
        certAlipayRequest.setRootCertContent(config.getAliPayRootCertContent());
        // 構(gòu)造client
        try {
            return new DefaultAlipayClient(certAlipayRequest);
        } catch (AlipayApiException e) {
            log.error("創(chuàng)建AliPayClient異常:{}", e);
            return null;
        }
    }

    private String timeoutExpress(Integer timeoutExpress) {
        if (timeoutExpress == null) {
            return "15m";
        }
        return String.format("%dm", timeoutExpress);
    }

}

到此即可使用,上述中二維碼和H5支付均已投入使用箍镜,APP和PC(未簽約)支付尚未驗證是否能喚起源祈。希望對大家有幫助。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末色迂,一起剝皮案震驚了整個濱河市香缺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歇僧,老刑警劉巖图张,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诈悍,居然都是意外死亡祸轮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門侥钳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來适袜,“玉大人,你說我怎么就攤上這事慕趴』居” “怎么了鄙陡?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長躏啰。 經(jīng)常有香客問我趁矾,道長,這世上最難降的妖魔是什么给僵? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任毫捣,我火速辦了婚禮,結(jié)果婚禮上帝际,老公的妹妹穿的比我還像新娘蔓同。我一直安慰自己,他們只是感情好蹲诀,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布斑粱。 她就那樣靜靜地躺著,像睡著了一般脯爪。 火紅的嫁衣襯著肌膚如雪则北。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天痕慢,我揣著相機與錄音尚揣,去河邊找鬼。 笑死掖举,一個胖子當(dāng)著我的面吹牛快骗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播塔次,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼方篮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了励负?” 一聲冷哼從身側(cè)響起恭取,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎熄守,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耗跛,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡裕照,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了调塌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晋南。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖羔砾,靈堂內(nèi)的尸體忽然破棺而出负间,到底是詐尸還是另有隱情偶妖,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布政溃,位于F島的核電站趾访,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏董虱。R本人自食惡果不足惜扼鞋,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望愤诱。 院中可真熱鬧云头,春花似錦、人聲如沸淫半。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽科吭。三九已至昏滴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間砌溺,已是汗流浹背影涉。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留规伐,地道東北人蟹倾。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像猖闪,于是被迫代替她去往敵國和親鲜棠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容