SpringBoot(二) SpringBoot開發(fā)實(shí)例

本文主要是項(xiàng)目開發(fā)過程中常用功能的總結(jié)。
下文我提到的部分功能都可以結(jié)合Hutool來實(shí)現(xiàn)。所以先來了解一下Hutool文檔:https://www.hutool.club/docs/#/

一 發(fā)送郵件
1 引入依賴

我們可以使用Hutool的MailUtil來發(fā)送郵箱价匠,需要加入Hutool和MailUtil的依賴店归。

// hutool依賴
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.0.3</version>
</dependency>
// 發(fā)送郵件依賴
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>
2 郵箱配置

要想實(shí)現(xiàn)發(fā)郵件功能,就得配置發(fā)件郵箱【現(xiàn)在我以qq郵箱和騰訊企業(yè)郵箱為例說明坯门。

  • qq郵箱
    登錄郵箱微饥,依次點(diǎn)擊設(shè)置-->賬戶-->POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服務(wù),看到如下界面:


    默認(rèn)情況下,POP3/SMTP服務(wù)是關(guān)閉的田盈,我們需要開啟它畜号,按照提示缴阎,我們最終可以得到授權(quán)碼允瞧,這個我們后面需要用到。

  • 騰訊企業(yè)郵箱
    企業(yè)郵箱不需要授權(quán)碼蛮拔。

3 功能實(shí)現(xiàn)

在classpath(在標(biāo)準(zhǔn)Maven項(xiàng)目中為src/main/resources)目錄或在classpath的config目錄下新建mail.setting文件述暂。
mail.setting之所以要放到上述目錄下,是Hutool源碼中所規(guī)定的建炫。

   #收件人郵箱
    to = xxx 
    # 騰訊企業(yè)郵箱配置
    # 郵件服務(wù)器的SMTP地址
    host = smtp.exmail.qq.com
    # 郵件服務(wù)器的SMTP端口
    port = 465
    # 發(fā)件人郵箱(必須正確畦韭,否則發(fā)送失敗)
    from = xxx
    # 用戶名肛跌,默認(rèn)為發(fā)件人郵箱前綴艺配,我填的與from一致
    user = xxx
    # 授權(quán)碼
    pass = 上一步郵箱配置里獲得的授權(quán)碼(QQ郵箱)或密碼(騰訊企業(yè)郵箱)
    # 在使用QQ或Gmail郵箱時,需要強(qiáng)制開啟SSL支持
    sslEnable = true

    #qq郵箱配置
    # host = smtp.qq.com
    # 郵件服務(wù)器的SMTP端口
    # port = 465
    # 發(fā)件人(必須正確衍慎,否則發(fā)送失斪Α)
    # from = xxx@qq.com
    # 用戶名,默認(rèn)為發(fā)件人郵箱前綴
    # user = xxx@qq.com
    # 授權(quán)碼
    # pass = 上一步郵箱配置里獲得的授權(quán)碼
    # 在使用QQ或Gmail郵箱時稳捆,需要強(qiáng)制開啟SSL支持
    sslEnable = true

配置完成后赠法,就可以使用Hutool的發(fā)送郵件功能了。

//讀取classpath下的mail.setting
Setting setting = new Setting("mail.setting");
//獲取收件人
String to = setting.getStr("to");
MailUtil.send(to, "測試", “測試內(nèi)容”, true);

以上只是發(fā)送了普通文本郵件乔夯,參照官方文檔砖织,你也可以實(shí)現(xiàn)發(fā)送HTML格式的郵件并附帶附件以及群發(fā)的功能款侵。
下面我們來看看'mail.setting'配置文件如何調(diào)用的,進(jìn)入MailUtil.send源碼侧纯,最終可以看到:

MailUtil.java

可以看到第一行Mail.create構(gòu)造了一個mail對象新锈,構(gòu)造方法如下:
Mail.java

我們可以看出也可以通過傳入MailAccount的方式傳入配置。這在官方文檔中也給出了相應(yīng)示例眶熬。如果用戶沒有傳入一個mailAccount壕鹉,系統(tǒng)會從GlobalMailAccount中取。
GlobalMailAccount.java

而系統(tǒng)取得mailAccount的路徑是以下三個:
MailAccount.java

說明我們的mail.setting按照以上三種方式放都是可以的聋涨。

二 生成二維碼

現(xiàn)在需要生成類似下圖的二維碼圖片晾浴,包括背景圖片(背景圖片來源),二維碼和文字牍白。

效果圖

  • 生成二維碼是第一步
    Hutool的QrCodeUtil可以生成二維碼脊凰,引入依賴
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.3.3</version>
</dependency>
  • 生成二維碼,拼接背景圖片并添加文字
 public static void main(String[] args) throws IOException {
        QrConfig config = new QrConfig(400, 380);
        // 高糾錯級別
        config.setErrorCorrection(ErrorCorrectionLevel.H);
        config.setMargin(1);
        File output = new File("f:/test/output.jpg");
       //生成二維碼
        File file = QrCodeUtil.generate("http://192.168.168.132:9528/faq", config, output);
        //合并背景圖片和二維碼
        if (file.exists()) {
            BufferedImage bi1 = null;
            BufferedImage bi2 = null;
            BufferedImage destImg = null;
            //讀取背景圖片
            File background = new File("f:/test/background.png");
            //讀取二維碼圖片
            bi1 = ImageIO.read(background);
            //讀取背景圖片
            bi2 = ImageIO.read(file);
            destImg = PictureMerge.mergeImage(bi1, bi2, true, 110, 140);
            //為圖片添加文字
            destImg = PictureMerge.drawTextInImg(destImg, new FontText("ID  :  TI1911080001", "#333333", 30, "Arial"), 180, 530);
            boolean result = PictureMerge.saveImage(destImg, "f:/test/","new.jpg", "jpg");
        }
}
  • 圖片文字拼接工具類
/**
 * 圖片合并工具類
 *
 * @author : TiaNa
 * @createdDate : 2019/10/21
 * @updatedDate
 */

public class PictureMerge {
    /**
     * @param fileUrl 文件絕對路徑或相對路徑
     * @return 讀取到的緩存圖像
     * @throws IOException 路徑錯誤或者不存在該文件時拋出IO異常
     */
    public static BufferedImage getBufferedImage(String fileUrl) throws IOException {
        File f = new File(fileUrl);
        return ImageIO.read(f);
    }

    /**
     * @param savedImg 待保存的圖像
     * @param saveDir  保存的目錄
     * @param fileName 保存的文件名茂腥,必須帶后綴狸涌,比如 "beauty.jpg"
     * @param format   文件格式:jpg、png或者bmp
     * @return
     */
    public static boolean saveImage(BufferedImage savedImg, String saveDir, String fileName, String format) {
        boolean flag = false;
        // 先檢查保存的圖片格式是否正確
        String[] legalFormats = {"jpg", "JPG", "png", "PNG", "bmp", "BMP"};
        int i = 0;
        for (i = 0; i < legalFormats.length; i++) {
            if (format.equals(legalFormats[i])) {
                break;
            }
        }
        if (i == legalFormats.length) { // 圖片格式不支持
            System.out.println("不是保存所支持的圖片格式!");
            return false;
        }

        // 再檢查文件后綴和保存的格式是否一致
        String postfix = fileName.substring(fileName.lastIndexOf('.') + 1);
        if (!postfix.equalsIgnoreCase(format)) {
            System.out.println("待保存文件后綴和保存的格式不一致!");
            return false;
        }

        String fileUrl = saveDir + fileName;
        File file = new File(fileUrl);
        try {
            flag = ImageIO.write(savedImg, format, file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 待合并的兩張圖必須滿足這樣的前提最岗,如果水平方向合并帕胆,則高度必須相等;如果是垂直方向合并般渡,寬度必須相等懒豹。
     * mergeImage方法不做判斷,自己判斷驯用。
     *
     * @param img1         待合并的第一張圖
     * @param img2         帶合并的第二張圖
     * @param isHorizontal 為true時表示水平方向合并脸秽,為false時表示垂直方向合并
     * @return 返回合并后的BufferedImage對象
     * @throws IOException
     */
    public static BufferedImage mergeImage(BufferedImage img1, BufferedImage img2, boolean isHorizontal, int startX, int startY) throws IOException {
        int w1 = img1.getWidth();
        int h1 = img1.getHeight();
        int w2 = img2.getWidth();
        int h2 = img2.getHeight();

        // 從圖片中讀取RGB
        int[] ImageArrayOne = new int[w1 * h1];
        ImageArrayOne = img1.getRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 逐行掃描圖像中各個像素的RGB到數(shù)組中
        int[] ImageArrayTwo = new int[w2 * h2];
        ImageArrayTwo = img2.getRGB(0, 0, w2, h2, ImageArrayTwo, 0, w2);

        // 生成新圖片
        BufferedImage DestImage = null;
        if (isHorizontal) { // 水平方向合并
            DestImage = new BufferedImage(w1, h1, BufferedImage.TYPE_INT_RGB);
            DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 設(shè)置上半部分或左半部分的RGB
            DestImage.setRGB(startX, startY, w2, h2, ImageArrayTwo, 0, w2); // 設(shè)置下半部分的RGB
        } else { // 垂直方向合并
            DestImage = new BufferedImage(w1, h1 + h2, BufferedImage.TYPE_INT_RGB);
            DestImage.setRGB(0, 0, w1, h1, ImageArrayOne, 0, w1); // 設(shè)置上半部分或左半部分的RGB
            DestImage.setRGB(0, h1, w2, h2, ImageArrayTwo, 0, w2); // 設(shè)置下半部分的RGB
        }
        return DestImage;
    }

    /**
     * <p>Title: getImageStream</p>
     * <p>Description: 獲取圖片InputStream</p>
     *
     * @param destImg
     * @return
     */
    public static InputStream getImageStream(BufferedImage destImg) {
        InputStream is = null;

        BufferedImage bi = destImg;

        ByteArrayOutputStream bs = new ByteArrayOutputStream();

        ImageOutputStream imOut;
        try {
            imOut = ImageIO.createImageOutputStream(bs);

            ImageIO.write(bi, "png", imOut);

            is = new ByteArrayInputStream(bs.toByteArray());

        } catch (IOException e) {
            e.printStackTrace();
        }
        return is;
    }

    /**
     * Description: 圖片上添加文字業(yè)務(wù)需求要在圖片上添加文字
     *
     * @param bimage
     * @param text
     * @param left
     */
    public static BufferedImage drawTextInImg(BufferedImage bimage, FontText text, int left, int top) {
        Graphics2D g = bimage.createGraphics();
        g.setColor(getColor(text.getColor()));
        g.setBackground(Color.white);
        Font font = new Font(text.getFont(), Font.BOLD,
                text.getSize());
        g.setFont(font);
        g.drawString(text.getText(), left, top);
        g.dispose();
        return bimage;
    }

    // color #2395439
    public static Color getColor(String color) {
        if (color.charAt(0) == '#') {
            color = color.substring(1);
        }
        if (color.length() != 6) {
            return null;
        }
        try {
            int r = Integer.parseInt(color.substring(0, 2), 16);
            int g = Integer.parseInt(color.substring(2, 4), 16);
            int b = Integer.parseInt(color.substring(4), 16);
            return new Color(r, g, b);
        } catch (NumberFormatException nfe) {
            return null;
        }
    }
  • 字體類
/**
 * 字體
 *
 * @author : TiaNa
 * @createdDate : 2019/10/21
 * @updatedDate
 */
@Data
public class FontText {

    private String text;

    private String color;

    private Integer size;

    private String font;

    public FontText(String text, String color,
                    Integer size, String font) {
        super();
        this.text = text;
        this.color = color;
        this.size = size;
        this.font = font;
    }

    public FontText() {
    }
}
三 excel表格導(dǎo)入導(dǎo)出
  • 這里也是使用的Hutool工具實(shí)現(xiàn)
@Slf4j
public class ExcelUtils {

    /**
     * 讀取excel表格內(nèi)容返回List<Bean>
     *
     * @param inputStream excel文件流
     * @param head        表頭數(shù)組
     * @param headerAlias 表頭別名數(shù)組
     * @param bean        返回的Bean對象
     * @return
     */
    public static <T> List<T> importExcel(InputStream inputStream, String[] head, String[] headerAlias, Class<T> bean) {
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        List<Object> header = reader.readRow(1);
        //替換表頭關(guān)鍵字
        if (ArrayUtils.isEmpty(head) || ArrayUtils.isEmpty(headerAlias) || head.length != headerAlias.length) {
           log.error("導(dǎo)入的excel表,表頭格式與設(shè)定規(guī)則不一致");
        } else {
            for (int i = 0; i < head.length; i++) {
                if (head[i].equals(header.get(i))) {
                    reader.addHeaderAlias(head[i], headerAlias[i]);
                } else {
                    log.error("導(dǎo)入的excel表蝴乔,表頭格式與設(shè)定規(guī)則不一致");
                }
            }
        }
        //讀取指點(diǎn)行開始的表數(shù)據(jù)(以下介紹的三個參數(shù)也可以使用動態(tài)傳入记餐,根據(jù)個人業(yè)務(wù)情況修改)
        //1:表頭所在行數(shù)  2:數(shù)據(jù)開始讀取位置 3:映射返回的Bean對象
        List<T> read = reader.read(1, 2, bean);
        return read;
    }

    /**
     * 導(dǎo)出excel表格內(nèi)容
     *
     * @param filename    文件名
     * @param head        表頭數(shù)組
     * @param headerAlias 表頭別名數(shù)組
     * @param list        導(dǎo)入的數(shù)據(jù)
     * @return
     */
    public static void exportExcel(String filename, String[] head, String[] headerAlias, List list) {
        ExcelWriter writer = ExcelUtil.getWriter(filename);
        List rows = CollUtil.newArrayList(list);
        if (ArrayUtils.isEmpty(head) || ArrayUtils.isEmpty(headerAlias) || head.length != headerAlias.length) {
             log.error("導(dǎo)入的excel表,表頭屬性與設(shè)定規(guī)則不一致");
        } else {
            for (int i = 0; i < head.length; i++) {
                writer.addHeaderAlias(head[i], headerAlias[i]);
            }
        }

        // 一次性寫出內(nèi)容薇正,使用默認(rèn)樣式片酝,強(qiáng)制輸出標(biāo)題
        writer.write(rows, true);
        // 關(guān)閉writer,釋放內(nèi)存
        writer.close();
    }
}
  • 測試
@RunWith(SpringRunner.class)
@SpringBootTest
public class ExcelTest {

    @Autowired
    private InstallService installService;

    @Test
    public void exportExcel(){
        List<DeviceInstall> list = installService.list();
        String name = "測試單-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"));
       //list里實(shí)體字段要和excelHead 保持一致
        String[] excelHeadAlias = {"編號", "日期", "聯(lián)系人", "聯(lián)系人電話", "描述"};
        String[] excelHead = {"Id", "installUserPhone", "installLinkUser", "installLinkPhone", "installNotes"};
        ExcelUtils.exportExcel("F:/test/excel/".concat(name).concat(".xlsx"), excelHead, excelHeadAlias, list);
    }
四 Redis緩存用戶登錄信息挖腰,并實(shí)現(xiàn)token驗(yàn)證

?系統(tǒng)中需要緩存用戶登錄信息和驗(yàn)證碼雕沿,在此之前我使用session緩存,在單服務(wù)器中這樣也沒太大問題曙聂,但當(dāng)服務(wù)部署到集群環(huán)境晦炊,就會出現(xiàn)session不一致的問題,這里是# 分布式系統(tǒng)session一致性的問題,我最終的解決方案就是用Redis緩存用戶信息断国。

1 實(shí)現(xiàn)思路:

  • 用戶登錄時贤姆,校驗(yàn)成功后,產(chǎn)生uuid稳衬,以uuid為key霞捡,用戶信息為value存入Redis,過期時長為15分鐘薄疚。此外碧信,我還需要將uuid傳給前端。
  • 用戶調(diào)用其他接口時街夭,請求頭中需加入登錄時返回的uuid值砰碴,后端攔截器攔截到到有效的uuid時,要相對應(yīng)的給Redis中的uuid續(xù)命板丽,延長過期時間呈枉。

2 實(shí)現(xiàn)過程:
首先需要學(xué)習(xí)Redis基礎(chǔ),如果對Springboot整合Redis不熟悉埃碱,可以參考文章:idea整合springboot+redis,下面我們看代碼

  • 用戶登錄實(shí)現(xiàn)類
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public UserVO login(String account, String pwd, HttpSession session) {
       //根據(jù)用戶賬戶查詢用戶信息
        LambdaQueryWrapper<User> query = Wrappers.lambdaQuery();
        query.eq(User::getAccount, account);
        User user = getOne(query);
        if (user != null && pwd.equals(user.getPassword())) {
                //登錄信息存儲在redis中
                String uuid = UUID.randomUUID().toString();
                user.setToken(uuid);
                redisUtils.set(uuid, user, 900);
                return user;
            }
        }
        throw new MyException("用戶名或密碼錯誤");
    }
public class UserInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisUtils redisUtils;

    /**
     * 在請求處理之前進(jìn)行調(diào)用(Controller方法調(diào)用之前)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws IOException {
        //獲取token
        String token = request.getHeader("token");
        //不攔截options請求
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            return true;
        }

        //查詢redis存儲的用戶信息
       if (!StringUtils.isBlank(token ) && redisUtils.exists(token )) {
            //更新登錄有效時間
            redisUtils.expire(redisUser, 900);
            return true;
        } else {
            throw new DataValidationException("用戶身份信息錯誤");
        }
    }

    /**
     * 請求處理之后進(jìn)行調(diào)用,但是在視圖被渲染之前(Controller方法調(diào)用之后)
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView mv)
            throws Exception {

    }

    /**
     * 在整個請求結(jié)束之后被調(diào)用砚殿,也就是在DispatcherServlet 渲染了對應(yīng)的視圖之后執(zhí)行 (主要是用于進(jìn)行資源清理工作)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex)
            throws Exception {

    }

    public void returnErrorResponse(HttpServletResponse response, Result result)
            throws IOException, UnsupportedEncodingException {
        OutputStream out = null;
        try {
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/json");
            out = response.getOutputStream();

            out.write(JSONUtil.toJsonStr(result).getBytes("utf-8"));
            out.flush();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }
}
  • 攔截器配置啃憎,不攔截登錄請求和swagger文檔,且必須配置跨域
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Bean
    public UserInterceptor getUserInterceptor() {
        return new UserInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
         * 攔截器按照順序執(zhí)行
         */
        registry.addInterceptor(getUserInterceptor())
                .excludePathPatterns("/api/v010/users/login")
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");

    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    //支持跨域請求
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600);
        super.addCorsMappings(registry);
    }
}

3 測試:

  • 訪問登錄接口http://localhost:8080/users/login似炎,獲取uuid
    登錄接口返回?cái)?shù)據(jù)
  • 訪問其他接口時,請求頭加上uuid就能請求成功辛萍,否則拋出異常


    header
五 全局異常處理

這里寫的非常詳細(xì)了:# SpringBoot 全局異常處理詳解

六 權(quán)限管理

在所有系統(tǒng)中,都有權(quán)限管理的功能名党,下面這篇文章可以提供很多思路
一個基于SpringBoot2+Shiro的權(quán)限管理系統(tǒng)

七 Jmeter性能測試

# Jmeter性能測試 入門

八 SpringBoot集成極光推送

https://blog.csdn.net/x541211190/article/details/81123829

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叹阔,一起剝皮案震驚了整個濱河市挠轴,隨后出現(xiàn)的幾起案子传睹,更是在濱河造成了極大的恐慌,老刑警劉巖岸晦,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欧啤,死亡現(xiàn)場離奇詭異,居然都是意外死亡启上,警方通過查閱死者的電腦和手機(jī)邢隧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冈在,“玉大人倒慧,你說我怎么就攤上這事。” “怎么了纫谅?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵炫贤,是天一觀的道長。 經(jīng)常有香客問我付秕,道長兰珍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任询吴,我火速辦了婚禮掠河,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猛计。我一直安慰自己唠摹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布奉瘤。 她就那樣靜靜地躺著跃闹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪毛好。 梳的紋絲不亂的頭發(fā)上望艺,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天,我揣著相機(jī)與錄音肌访,去河邊找鬼找默。 笑死,一個胖子當(dāng)著我的面吹牛吼驶,可吹牛的內(nèi)容都是我干的惩激。 我是一名探鬼主播,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蟹演,長吁一口氣:“原來是場噩夢啊……” “哼风钻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酒请,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤骡技,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后羞反,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體布朦,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年昼窗,在試婚紗的時候發(fā)現(xiàn)自己被綠了是趴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡澄惊,死狀恐怖唆途,靈堂內(nèi)的尸體忽然破棺而出富雅,到底是詐尸還是另有隱情,我是刑警寧澤肛搬,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布吹榴,位于F島的核電站,受9級特大地震影響滚婉,放射性物質(zhì)發(fā)生泄漏图筹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一让腹、第九天 我趴在偏房一處隱蔽的房頂上張望远剩。 院中可真熱鬧,春花似錦骇窍、人聲如沸瓜晤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痢掠。三九已至,卻和暖如春嘲恍,著一層夾襖步出監(jiān)牢的瞬間足画,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工佃牛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淹辞,地道東北人。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓俘侠,卻偏偏與公主長得像象缀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子爷速,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,442評論 2 359

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