随笔篇-多种类型文件加水印

1.前言

最近遇到要给pdf,excel,word,html文件加水印的需求,网上大部分实现的只是其中一种,并没有一个完整的实现方式,因此对现有的资料进行整合

支持pdf,excel,wordhtml文件多水印支持

2.依赖

文件水印是基于apach-poiitex来实现,因此需要导入一下依赖

<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>4.1.2</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>ooxml-schemas</artifactId>
        <version>1.4</version>
    </dependency>

    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext-asian</artifactId>
        <version>5.2.0</version>
    </dependency>

    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itextpdf</artifactId>
        <version>5.5.13.1</version>
    </dependency>
</dependencies>

3.代码

文件加水印代码如下:

package com.tomato.util;

import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.stream.Stream;

/**
 * <p>
 * Copyright: (C), 2022/3/27 10:47
 * <p>
 * Company: tomato
 *
 * @author 秃头猿猿
 * @version 1.0
 */
public class WaterMarkUtils {

    private static final String fontName = "microsoft-yahei";
    private static final String fontSize = "0.1pt";
    private static final String fontColor = "#d0d0d0";
    private static final Integer widthPerWord = 5;
    private static final String styleRotation = "-45";
    private static Integer styleTop = 0;

    /**
     * pdf 增加水印
     *
     * @param srcFile
     * @param destFile
     * @param waterMarkContent
     * @throws Exception
     */
    public static void addPDFWaterMark(File srcFile, File destFile, String... waterMarkContent) throws Exception {
        addPDFWaterMark(new FileInputStream(srcFile), new FileOutputStream(destFile), waterMarkContent);
    }

    public static void addPDFWaterMark(File srcFile, OutputStream outputStream, String... waterMarkContent) throws Exception {
        addPDFWaterMark(new FileInputStream(srcFile), outputStream, waterMarkContent);
    }

    public static void addPDFWaterMark(InputStream inputStream, File destFile, String... waterMarkContent) throws Exception {
        addPDFWaterMark(inputStream, new FileOutputStream(destFile), waterMarkContent);
    }

    /**
     * pdf 增加水印
     *
     * @param inputStream      源文件流
     * @param outputStream     目的文件流
     * @param waterMarkContent 水印内容
     * @throws Exception
     */
    private static void addPDFWaterMark(InputStream inputStream, OutputStream outputStream, String... waterMarkContent) throws Exception {
        // 原PDF文件
        PdfReader reader = new PdfReader(inputStream);
        // 输出的PDF文件内容
        PdfStamper stamper = new PdfStamper(reader, outputStream);
        try {

            // 字体 来源于 itext-asian JAR包
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

            PdfGState gs = new PdfGState();
            // 设置透明度
            gs.setFillOpacity(0.3f);
            gs.setStrokeOpacity(0.4f);
            int totalPage = reader.getNumberOfPages() + 1;
            for (int i = 1; i < totalPage; i++) {
                // 内容上层
                float x = reader.getPageSize(i).getWidth();
                float y = reader.getPageSize(i).getHeight();
                PdfContentByte content = stamper.getOverContent(i);
                content.beginText();
                // 字体添加透明度
                content.setGState(gs);
                // 添加字体大小等
                content.setFontAndSize(baseFont, 15);
                // 一共七行,每行三个
                for (int j = 0; j < 3; j++) {
                    for (int k = 0; k < 7; k++) {
                        int ji = 0; // 多个水印之间的间隔
                        for (String water : waterMarkContent) {
                            //showTextAligned 方法的参数(文字对齐方式,位置内容,输出水印X轴位置,Y轴位置,旋转角度)
                            content.showTextAligned(Element.ALIGN_CENTER, water, x / 3 * j + 90, y / 7 * k - ji, 25);
                            ji = 20;
                        }
                    }
                }
                content.endText();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭
            if (stamper != null) {
                stamper.close();
            }
            if (reader != null) {
                reader.close();
            }
        }
    }

    /**
     * excel 加水印
     *
     * @param srcFile
     * @param destFile
     * @param waterMarkContent
     * @throws Exception
     */
    public static void addExcelWaterMark(File srcFile, File destFile, String... waterMarkContent) throws Exception {
        addExcelWaterMark(new FileInputStream(srcFile), new FileOutputStream(destFile), waterMarkContent);
    }

    public static void addExcelWaterMark(File srcFile, OutputStream outputStream, String... waterMarkContent) throws Exception {
        addExcelWaterMark(new FileInputStream(srcFile), outputStream, waterMarkContent);
    }

    public static void addExcelWaterMark(InputStream inputStream, File destFile, String... waterMarkContent) throws Exception {
        addExcelWaterMark(inputStream, new FileOutputStream(destFile), waterMarkContent);
    }

    /**
     * excel添加水印
     *
     * @param inputStream   原始文件流
     * @param outputStream  生成文件流
     * @param waterMarkName 水印内容
     */
    public static void addExcelWaterMark(InputStream inputStream, OutputStream outputStream, String... waterMarkName) throws Exception {
        BufferedImage image = createWaterMarkImage(waterMarkName);
        // 导出到字节流B
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, "png", os);

        XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
        int pictureIdx = workbook.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);
        POIXMLDocumentPart poixmlDocumentPart = workbook.getAllPictures().get(pictureIdx);
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {//获取每个Sheet表
            XSSFSheet sheet = workbook.getSheetAt(i);
            PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
            String relType = XSSFRelation.IMAGES.getRelation();
            PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
            sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
        }

        workbook.write(outputStream);
    }


    public static void addWordWaterMark(File srcFile, File destFile, String... waterMarkContent) throws Exception {
        addWordWaterMark(new FileInputStream(srcFile), new FileOutputStream(destFile), waterMarkContent);
    }

    public static void addWordWaterMark(File srcFile, OutputStream outputStream, String... waterMarkContent) throws Exception {
        addWordWaterMark(new FileInputStream(srcFile), outputStream, waterMarkContent);
    }

    public static void addWordWaterMark(InputStream inputStream, File destFile, String... waterMarkContent) throws Exception {
        addWordWaterMark(inputStream, new FileOutputStream(destFile), waterMarkContent);
    }


    /**
     * word加水印
     *
     * @param inputStream
     * @param outputStream
     * @param customText
     * @throws Exception
     */
    public static void addWordWaterMark(InputStream inputStream, OutputStream outputStream, String... customText) throws Exception {
        XWPFDocument doc = new XWPFDocument(inputStream);
        // 把整页都打上水印
        for (int lineIndex = -5; lineIndex < 20; lineIndex++) {
            styleTop = 100 * lineIndex;
            waterMarkDocXDocument_0(doc, customText);
        }
        doc.write(outputStream);
    }


    public static void addHtmlWaterMark(File srcFile, File destFile, String... waterMarkContent) throws Exception {
        addHtmlWaterMark(new FileInputStream(srcFile), new FileOutputStream(destFile, Boolean.TRUE), waterMarkContent);
    }

    public static void addHtmlWaterMark(File srcFile, OutputStream outputStream, String... waterMarkContent) throws Exception {
        addHtmlWaterMark(new FileInputStream(srcFile), outputStream, waterMarkContent);
    }

    public static void addHtmlWaterMark(InputStream inputStream, File destFile, String... waterMarkContent) throws Exception {
        addHtmlWaterMark(inputStream, new FileOutputStream(destFile, Boolean.TRUE), waterMarkContent);
    }


    public static void addHtmlWaterMark(InputStream inputStream, OutputStream outputStream, String... customText) throws Exception {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        PrintWriter pw = new PrintWriter(outputStream);
        String line = null;
        while ((line = bufferedReader.readLine()) != null) {
            pw.append(line);
        }
        String waterMarkCode = "<SCRIPT LANGUAGE=\"JavaScript\">\n" +
                "\n" +
                "    watermark({watermark_txt: '{0}'})\n" +
                "\n" +
                "    function watermark(settings) {\n" +
                "    var defaultSettings={\n" +
                "        watermark_txt:\"text\",\n" +
                "        watermark_x:20,//水印起始位置x轴坐标\n" +
                "        {1}," +
                "        watermark_rows:0,//水印行数\n" +
                "        watermark_cols:30,//水印列数\n" +
                "        watermark_x_space:100,//水印x轴间隔\n" +
                "        watermark_y_space:50,//水印y轴间隔\n" +
                "        watermark_color:'#aaa',//水印字体颜色\n" +
                "        watermark_alpha:0.4,//水印透明度\n" +
                "        watermark_fontsize:'14px',//水印字体大小\n" +
                "        watermark_font:'微软雅黑',//水印字体\n" +
                "        watermark_width:210,//水印宽度\n" +
                "        watermark_height:80,//水印长度\n" +
                "        watermark_angle:15//水印倾斜度数\n" +
                "    };\n" +
                "    if(arguments.length===1&&typeof arguments[0] ===\"object\" )\n" +
                "    {\n" +
                "        var src=arguments[0]||{};\n" +
                "        for(key in src)\n" +
                "        {\n" +
                "            if(src[key]&&defaultSettings[key]&&src[key]===defaultSettings[key])\n" +
                "                continue;\n" +
                "            else if(src[key])\n" +
                "                defaultSettings[key]=src[key];\n" +
                "        }\n" +
                "    }\n" +
                "\n" +
                "    var oTemp = document.createDocumentFragment();\n" +
                "\n" +
                "    var page_width = Math.max(document.body.scrollWidth,document.body.clientWidth);\n" +
                "    var cutWidth = page_width*0.0150;\n" +
                "    var page_width=page_width-cutWidth;\n" +
                "    var page_height = Math.max(document.body.scrollHeight,document.body.clientHeight)+450;\n" +
                "    // var page_height = document.body.scrollHeight+document.body.scrollTop;\n" +
                "    if (defaultSettings.watermark_cols == 0 || (parseInt(defaultSettings.watermark_x + defaultSettings.watermark_width *defaultSettings.watermark_cols + defaultSettings.watermark_x_space * (defaultSettings.watermark_cols - 1)) > page_width)) {\n" +
                "        defaultSettings.watermark_cols = parseInt((page_width-defaultSettings.watermark_x+defaultSettings.watermark_x_space) / (defaultSettings.watermark_width + defaultSettings.watermark_x_space));\n" +
                "        defaultSettings.watermark_x_space = parseInt((page_width - defaultSettings.watermark_x - defaultSettings.watermark_width * defaultSettings.watermark_cols) / (defaultSettings.watermark_cols - 1));\n" +
                "    }\n" +
                "    if (defaultSettings.watermark_rows == 0 || (parseInt(defaultSettings.watermark_y + defaultSettings.watermark_height * defaultSettings.watermark_rows + defaultSettings.watermark_y_space * (defaultSettings.watermark_rows - 1)) > page_height)) {\n" +
                "        defaultSettings.watermark_rows = parseInt((defaultSettings.watermark_y_space + page_height - defaultSettings.watermark_y) / (defaultSettings.watermark_height + defaultSettings.watermark_y_space));\n" +
                "        defaultSettings.watermark_y_space = parseInt(((page_height - defaultSettings.watermark_y) - defaultSettings.watermark_height * defaultSettings.watermark_rows) / (defaultSettings.watermark_rows - 1));\n" +
                "    }\n" +
                "    var x;\n" +
                "    var y;\n" +
                "    for (var i = 0; i < defaultSettings.watermark_rows; i++) {\n" +
                "        y = defaultSettings.watermark_y + (defaultSettings.watermark_y_space + defaultSettings.watermark_height) * i;\n" +
                "        for (var j = 0; j < defaultSettings.watermark_cols; j++) {\n" +
                "            x = defaultSettings.watermark_x + (defaultSettings.watermark_width + defaultSettings.watermark_x_space) * j;\n" +
                "\n" +
                "            var mask_div = document.createElement('div');\n" +
                "            mask_div.id = 'mask_div' + i + j;\n" +
                "            mask_div.className = 'mask_div';\n" +
                "            mask_div.appendChild(document.createTextNode(defaultSettings.watermark_txt));\n" +
                "            //设置水印div倾斜显示\n" +
                "            mask_div.style.webkitTransform = \"rotate(-\" + defaultSettings.watermark_angle + \"deg)\";\n" +
                "            mask_div.style.MozTransform = \"rotate(-\" + defaultSettings.watermark_angle + \"deg)\";\n" +
                "            mask_div.style.msTransform = \"rotate(-\" + defaultSettings.watermark_angle + \"deg)\";\n" +
                "            mask_div.style.OTransform = \"rotate(-\" + defaultSettings.watermark_angle + \"deg)\";\n" +
                "            mask_div.style.transform = \"rotate(-\" + defaultSettings.watermark_angle + \"deg)\";\n" +
                "            mask_div.style.visibility = \"\";\n" +
                "            mask_div.style.position = \"absolute\";\n" +
                "            mask_div.style.left = x + 'px';\n" +
                "            mask_div.style.top = y + 'px';\n" +
                "            mask_div.style.overflow = \"hidden\";\n" +
                "            mask_div.style.zIndex = \"9999\";\n" +
                "            mask_div.style.pointerEvents='none';//pointer-events:none  让水印不遮挡页面的点击事件\n" +
                "            //mask_div.style.border=\"solid #eee 1px\";\n" +
                "            mask_div.style.opacity = defaultSettings.watermark_alpha;\n" +
                "            mask_div.style.fontSize = defaultSettings.watermark_fontsize;\n" +
                "            mask_div.style.fontFamily = defaultSettings.watermark_font;\n" +
                "            mask_div.style.color = defaultSettings.watermark_color;\n" +
                "            mask_div.style.textAlign = \"center\";\n" +
                "            mask_div.style.width = defaultSettings.watermark_width + 'px';\n" +
                "            mask_div.style.height = defaultSettings.watermark_height + 'px';\n" +
                "            mask_div.style.display = \"block\";\n" +
                "            oTemp.appendChild(mask_div);\n" +
                "        };\n" +
                "    };\n" +
                "    document.body.appendChild(oTemp);\n" +
                "} \n" +
                "</SCRIPT>";

        int y = 20;
        for (String text : customText) {
            String replace = waterMarkCode.replace("{0}", text).replace("{1}", "watermark_y:" + y);
            pw.println(replace);
            y += 20;
        }

        pw.flush();
        pw.close();
        bufferedReader.close();
        pw.close();
    }


    /**
     * 为文档添加水印
     *
     * @param doc        需要被处理的docx文档对象
     * @param customText 需要添加的水印文字
     */
    private static void waterMarkDocXDocument_0(XWPFDocument doc, String... customText) {
        // 如果之前已经创建过 DEFAULT 的Header,将会复用
        XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
        int size = header.getParagraphs().size();
        if (size == 0) {
            header.createParagraph();
        }
        CTP ctp = header.getParagraphArray(0).getCTP();
        byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
        byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
        ctp.setRsidP(rsidr);
        ctp.setRsidRDefault(rsidrdefault);
        CTPPr ppr = ctp.addNewPPr();
        ppr.addNewPStyle().setVal("Header");
        // 开始加水印
        CTR ctr = ctp.addNewR();
        CTRPr ctrpr = ctr.addNewRPr();
        ctrpr.addNewNoProof();
        CTGroup group = CTGroup.Factory.newInstance();
        CTShapetype shapetype = group.addNewShapetype();
        CTTextPath shapeTypeTextPath = shapetype.addNewTextpath();
        shapeTypeTextPath.setOn(STTrueFalse.T);
        shapeTypeTextPath.setFitshape(STTrueFalse.T);
        CTLock lock = shapetype.addNewLock();
        lock.setExt(STExt.VIEW);
        CTShape shape = group.addNewShape();
        shape.setId("PowerPlusWaterMarkObject");
        shape.setSpid("_x0000_s102");
        shape.setType("#_x0000_t136");
        // 设置形状样式(旋转,位置,相对路径等参数)
        //shape.setStyle(getShapeStyle(customText));
        shape.setFillcolor(fontColor);
        // 字体设置为实心
        shape.setStroked(STTrueFalse.FALSE);
        // 绘制文本的路径
        CTTextPath shapeTextPath = shape.addNewTextpath();
        // 设置文本字体与大小
        shapeTextPath.setStyle("font-family:" + fontName + ";font-size:" + fontSize);
        //shapeTextPath.setString(customText);
        //CTPicture pict = ctr.addNewPict();
        // pict.set(group);

        int position = 0;
        for (String s : customText) {
            // 水印文字之间使用50个空格分隔
            s = s + repeatString("\t", 45);
            // 一行水印重复水印文字次数
            s = repeatString(s, 5);
            // 设置形状样式(旋转,位置,相对路径等参数)
            shape.setStyle(getShapeStyle(s, position));
            shapeTextPath.setString(s);
            CTPicture pict = ctr.addNewPict();
            pict.set(group);
            position += 30;
        }


    }

    /**
     * 构建Shape的样式参数
     *
     * @param customText
     * @return
     */
    private static String getShapeStyle(String customText, Integer position) {
        StringBuilder sb = new StringBuilder();
        // 文本path绘制的定位方式
        sb.append("position: ").append("absolute");
        // 计算文本占用的长度(文本总个数*单字长度)
        sb.append(";width: ").append(customText.length() * widthPerWord).append("pt");
        // 字体高度
        sb.append(";height: ").append("10pt");
        sb.append(";z-index: ").append("-251654144");
        sb.append(";mso-wrap-edited: ").append("f");
        // 设置水印的间隔,这是一个大坑,不能用top,必须要margin-top。
        sb.append(";margin-top: ").append(styleTop + position);
        sb.append(";mso-position-horizontal-relative: ").append("page");
        sb.append(";mso-position-vertical-relative: ").append("page");
        sb.append(";mso-position-vertical: ").append("left");
        sb.append(";mso-position-horizontal: ").append("center");
        sb.append(";rotation: ").append(styleRotation);
        return sb.toString();
    }


    /**
     * 将指定的字符串重复repeats次.
     */
    private static String repeatString(String pattern, int repeats) {
        StringBuilder buffer = new StringBuilder(pattern.length() * repeats);
        Stream.generate(() -> pattern).limit(repeats).forEach(buffer::append);
        return new String(buffer);
    }


    /**
     * 创建水印图片
     * excel
     *
     * @param waterMark 水印内容
     * @return
     */

    public static BufferedImage createWaterMarkImage(String... waterMark) {
        String[] textArray = waterMark;
        Font font = new Font(fontName, Font.PLAIN, 20);
        Integer width = 300;
        Integer height = 100;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 背景透明 开始
        Graphics2D g = image.createGraphics();
        image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g.dispose();
        // 背景透明 结束
        g = image.createGraphics();
        g.setColor(new Color(Integer.parseInt("#C5CBCF".substring(1), 16)));// 设定画笔颜色
        g.setFont(font);// 设置画笔字体
        g.shear(0.1, -0.26);// 设定倾斜度
        // 设置字体平滑
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        int y = 50;
        for (int i = 0; i < textArray.length; i++) {
            g.drawString(textArray[i], 0, y);// 画出字符串
            y = y + font.getSize();
        }
        g.dispose();// 释放画笔
        return image;
    }


}

4.演示

4.1 pdf

代码如下:

WaterMarkUtils.addPDFWaterMark(new File("D:\\Desktop\\watermark.pdf"),new File("D:\\Desktop\\watermark1.pdf"),"秃头猿猿","hello");

效果如下:

image-20220327105611251

4.2 word

代码如下:

WaterMarkUtils.addExcelWaterMark(new File("D:\\Desktop\\excel.xlsx"),new File("D:\\Desktop\\watermark1.xlsx"),"秃头猿猿","hello"); 

效果如下:

image-20220327105941116

4.3 word

代码如下:

WaterMarkUtils.addWordWaterMark(new File("D:\\Desktop\\word.docx"),new File("D:\\Desktop\\watermark1.docx"),"秃头猿猿","hello"); 

效果如下:

image-20220327110205727

4.4 html

代码如下:

WaterMarkUtils.addHtmlWaterMark(new File("D:\\Desktop\\watermark.html"),new File("D:\\Desktop\\watermark1.html"),"秃头猿猿","hello"); 

效果如下:

image-20220327110444661
最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容