14.自定义标签库开发(我的JavaEE笔记)

一、 自定义标签简介

自定义标签主要用于移除jsp页面中的java代码。工程tag

使用自定义标签移除jsp页面中的java代码,只需要完成以下两个步骤:
1.编写一个实现tag接口的java类(标签处理类)。
2.编写标签库描述符(tld)文件,在tld文件中对标签处理器类进行描述。

二、快速入门:使用标签输出客户机IP

这里我们先编写一个tld文件(itcast.tld):

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee web-jsptaglibrary_2_1.xsd">
    <tlib-version>1.0</tlib-version>
    <short-name>itcast</short-name><!-- tld文件名字 -->
    <uri>/itcast</uri><!-- 因为文件是放在WEB-INF下面 -->
    <tag>
        <name>viewIP</name><!-- 给标签起名 -->
        <tag-class>cn.itcast.web.tag.ViewIPTag</tag-class><!-- 类的完整类名 -->
        <body-content>empty</body-content><!-- 这里是操作标签体,如果不用,则使用empty -->
    </tag>
</taglib>

注意:标签<body-content>为empty表示标签起始和结束之间没有内容。如<a ..../>,而不能是<a>...</a>
说明:我们可以在MyEclipse中直接新建tld文件,然后填入相应的信息:

tld.png

其中Name是文件名,Version我们选择最高版本,Shortname一般填入文件名,由于文件放在WEB-INF 下面,所以uri地址是/itcast。

实现类(ViewIPTag.java)

package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
//自定义标签类,注意继承Tag接口
public class ViewIPTag implements Tag {
    
    private PageContext pageContext;//用于保存页面对象
    
    @Override
    public int doStartTag() throws JspException {
        HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
        //得到out隐式对象,用于输出
        JspWriter out = pageContext.getOut();
        //得到服务器地址
        String ip = request.getRemoteAddr();
        try {
            out.write(ip);
        } catch (IOException e) {
            //这里子类不能抛出比父类还多的异常
            throw new RuntimeException(e);
        }
        return 0;
    }
    
    @Override
    public void setPageContext(PageContext arg0) {
        this.pageContext = arg0;
    }
    
    @Override
    public int doEndTag() throws JspException {
        return 0;
    }
    @Override
    public Tag getParent() {
        return null;
    }
    @Override
    public void release() {}
    @Override
    public void setParent(Tag arg0) {}
}

使用(1.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/itcast" prefix="itcast"%><!-- 和之前使用EL标签一样,需要导入 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>客户机IP</title>
  </head>
  <body>
    您的IP是:<itcast:viewIP/>
    <%
        /* 等同于 */
        String ip = request.getRemoteAddr();
        out.write(ip);
     %>
  </body>
</html>

三、标签的执行过程

jsp引擎遇到自定义标签时,首先创建标签处理类的实例对象,然后按照jsp规范定义的通信规则依次调用它的方法。

1.jsp引擎实例化标签处理类之后,将调用setPageContext方法将jsp页面的pageContext对象传递给标签处理器,标签处理器以后可以通过这个pageContext对象与jsp页面进行通信。

2.setPageContext方法执行完后,web容器接着调用setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null。

3.调用了setPageContext方法和setParent方法之后,web容器执行到自定义标签的开始标签时,就会调用标签处理器的doStartTag方法。

4.web容器执行完自定义标签的标签体之后,就会接着去执行自定义标签的结束标签,此时,web容器就会调用doEndTag方法。

5.通常web容器执行完自定义标签后,标签处理器会驻留在内存中,为其它请求服务,直至停止web应用时,web容器才会调用release方法。

自定义标签功能扩展

开发人员在编写jsp页面时,经常还需要在页面中引入一些逻辑。例如:
(1)控制jsp页面某一部分内容是否执行
(2)控制整个jsp页面是否执行
(3)控制jsp页面内容重复执行
(4)修改jsp页面内容输出

自定义标签除了可以移除jsp页面的java代码,也可以实现以上功能。

例:控制jsp页面某一部分内容是否执行
TagDemo1.java

package cn.itcast.web.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;;
public class TagDemo1 extends TagSupport {

    @Override
    public int doStartTag() throws JspException {
        //return Tag.EVAL_BODY_INCLUDE;//返回此常量则会执行标签体
        return Tag.SKIP_BODY;//如果要跳过标签体,则使用此常量
        
    }
}

itcast.tld中

<tag>
  <name>demo1</name>
  <tag-class>cn.itcast.web.tag.TagDemo1</tag-class>
  <body-content>JSP</body-content>
</tag>

注意:此处<body-content>为JSP,必须是大写,表示标签之间有内容。内容接受所遇jsp语法,当然这里我们只是表示标签之间有内容,而内容执行不执行依据所定义的类。当然还可以是tagdependent和scriptless,但用的不多,此处不再详述。

注意:此处我们继承的是TagSupport类,因为每次继承Tag接口需要实现很多用不到的方法,于是这里我们继承此默认实现类可以简便一些。关于Tag接口的继承关系如下图:

JspTag接口.JPG

使用(2.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/itcast" prefix="itcast"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>控制jsp页面某一部分内容是否执行</title>
  </head>
  <body>
    <itcast:demo1>
        xxx
    </itcast:demo1>
  </body>
</html>

使用这个标签就表示xxx不会被执行。当然具体怎样控制我们可以在类中进行细化。

例:控制整个jsp页面是否执行
itcast.tld

    <tag>
        <name>demo2</name>
        <tag-class>cn.itcast.web.tag.TagDemo2</tag-class>
        <body-content>empty</body-content>
    </tag>

TagDemo2.java

package cn.itcast.web.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
public class TagDemo2 extends TagSupport {

    @Override
    public int doEndTag() throws JspException {
        return Tag.SKIP_PAGE;//此常量表示结束标签后买年余下的jsp页面不会执行
        //return Tag.EVAL_PAGE;//此常量表示会执行
    }
    
}

3.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/itcast" prefix="itcast"%>

<itcast:demo2/><!-- 即控制结束标签后面的jsp内容是否执行 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>控制整个jsp页面是否执行</title>
  </head>
  <body>
    
  </body>
</html>

例:控制jsp页面内容重复执行
itcast.tld

    <tag>
        <name>demo3</name>
        <tag-class>cn.itcast.web.tag.TagDemo3</tag-class>
        <body-content>JSP</body-content>
    </tag>

TagDemo3

package cn.itcast.web.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.IterationTag;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
public class TagDemo3 extends TagSupport {
    
    int x = 5;
    
    @Override
    public int doAfterBody() throws JspException {
        x--;
        //注意:控制标签体重复执行的时候需要的常量需要的不是Tag常量,而是IterationTag常量
        if(x > 0){
            return IterationTag.EVAL_BODY_AGAIN;
        }else{
            return IterationTag.SKIP_BODY;
        }
    }

    @Override
    public int doStartTag() throws JspException {
        //注意:要想重复执行,则首先要让标签体执行才行
        return Tag.EVAL_BODY_INCLUDE;
    }   
}

itcast.tld

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/itcast" prefix="itcast"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>控制页面重复执行</title>
  </head>
  <body>
    <itcast:demo3>
        这里的页面内容将重复执行
    </itcast:demo3>
  </body>
</html>

例:修改jsp页面内容输出
itcast.tld

    <tag>
        <name>demo4</name>
        <tag-class>cn.itcast.web.tag.TagDemo4</tag-class>
        <body-content>JSP</body-content>
    </tag>

TagDemo4

package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTag;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.Tag;
public class TagDemo4 extends BodyTagSupport {

    @Override
    public int doEndTag() throws JspException {
        //得到标签体内容字符串
        String content = this.getBodyContent().getString();
        //将标签体内容改为大写
        String result = content.toUpperCase();
        //得到out输入对象
        try {
            this.pageContext.getOut().write(result);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return Tag.EVAL_PAGE;//表示标签体余下的内容还要输出
    }

    @Override
    public int doStartTag() throws JspException {
        //要想修改标签体,则下面必须返回此常量
        return BodyTag.EVAL_BODY_BUFFERED;
    }   
}

5.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/itcast" prefix="itcast"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>修改标签体内容</title>
  </head>
  <body>
    <itcast:demo4>
        aaa
    </itcast:demo4>
  </body>
</html>

得到的输出结果是AAA。
最后,其实上面是一种很传统的方式,使用起来并不方便,一般我们很少使用。

四、简单标签

由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广,sun公司为降低标签技术的学习难度,在jsp2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。实现SimpleTag接口的标签通常称为简单标签。简单标签定义了5个方法:

  • setJspContext方法:用于把jsp页面的pageContext对象传递给标签处理器对象;
  • setParentgetParent方法:前者用于把父标签处理器对象传递给当前处理器对象。后者用于获得当前标签的父标签处理器对象。
  • setJspBody:用于把代表标签体的JspFragment对象传递给标签处理器对象。
  • doTag方法:用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知web容器不再执行jsp页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE的情况。

1.SimpleTag接口方法的执行顺序

(1)当web容器准备开始执行标签时,会调用如下方法完成标签的初始化:

  • 1.web容器调用标签处理器对象的setJspContext方法,将代表jsp页面的pageContext对象传递给标签处理器对象。
  • 2.web容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意:只有在标签存在父标签的情况下,web容器才会调用此方法。
  • 3.如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则web容器首先计算表达式的值,然后把值传递给标签处理器对象。
  • 4.如果简单标签有标签体,容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。

(2)执行标签时:
容器调用标签处理器的doTag方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。当然是先得到此对象。

2.JspFragment类

  • javax.servlet.jsp.tagext.JspFragment类是jsp2.0中定义的,它的实例对象代表jsp页面中的一段符合jsp语法规范的jsp片段,这段jsp片段中不能包含jsp脚本元素。

  • web容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理对象的setJspBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中定义了两个方法,如下所示:
    getJspContext方法:用于返回代表调用页面的JspContext对象。
    invoke方法:用于执行JspFragment对象所代表的jsp代码片段;参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果传递给参数out值为null,则将执行结果写入到JspContext.getOut方法返回的输出流对象中。(即写给浏览器)。

3.invoke方法详解

JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:

  • 1.在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体的内容;
  • 2.在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会别重复执行;
  • 3.若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。

4.使用简单标签实现之前传统标签完成的例子

例:使用简单标签实现控制标签体是否执行
WebRoot/WEB-INF/simpletag.tld

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee web-jsptaglibrary_2_1.xsd">
 <tlib-version>1.0</tlib-version>
 <short-name>simpleitcast</short-name>
 <uri>/simpleitcast</uri>
 
    <tag>
        <name>demo1</name>
        <tag-class>cn.itcast.web.simpletag.SimpleTagDemo1</tag-class>
        <!-- 这里注意:在简单标签中不允许使用JSP,因为新版的标签技术不允许在标签体中使用
        脚本代码,比如<%%>这样的,scriptless表示无脚本 -->
        <body-content>scriptless</body-content>
    </tag>
</taglib>

SimpleTagDemo1

package cn.itcast.web.simpletag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//使用简单标签控制标签体是否执行
public class SimpleTagDemo1 extends SimpleTagSupport {
    //简单标签使用此方法完成所有的业务逻辑
    @Override
    public void doTag() throws JspException, IOException {
        //得到JspFragment对象,即得到一段jsp片段
        JspFragment jf = this.getJspBody();
        //得到pageContext对象
        PageContext pageContext = (PageContext) this.getJspContext();
        jf.invoke(pageContext.getOut());
        //jf.invoke(null);//此行代码表示默认执行上面两行代码,表示默认传递给浏览器
    }   
}

WebRoot/simpletag/1.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/simpleitcast" prefix="itcast"%><!-- 这里我们前缀还是使用itcast -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>使用简单标签实现控制标签体是否执行</title>
  </head>
  <body>
    <itcast:demo1>
    xxxx
    </itcast:demo1>
  </body>
</html>

这里我们是允许标签体中的内容进行输出执行。输出xxxx。当然如果我们不想让标签体执行,那就不写

PageContext pageContext = (PageContext) this.getJspContext();
jf.invoke(pageContext.getOut());

或不写jf.invoke(null);

例:控制标签体重复执行
simpletag.tld

    <tag>
        <name>demo2</name>
        <tag-class>cn.itcast.web.simpletag.SimpleTagDemo2</tag-class>
        <body-content>scriptless</body-content>
    </tag>

SimpleTagDemo2

package cn.itcast.web.simpletag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//控制标签体重复执行多次
public class SimpleTagDemo2 extends SimpleTagSupport{

    @Override
    public void doTag() throws JspException, IOException {
        JspFragment jf = this.getJspBody();
        for(int i = 0; i < 10; i++){
            jf.invoke(null);
        }
    }
}

2.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/simpleitcast" prefix="itcast"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>控制标签体重复执行多次</title>
  </head>
  <body>
    <itcast:demo2>
    xxxx
    </itcast:demo2>
  </body>
</html>

例:修改标签体中的内容
simpletag.tld

    <tag>
        <name>demo3</name>
        <tag-class>cn.itcast.web.simpletag.SimpleTagDemo3</tag-class>
        <body-content>scriptless</body-content>
    </tag>

SimpleTagDemo3

package cn.itcast.web.simpletag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//修改标签体中的内容
public class SimpleTagDemo3 extends SimpleTagSupport{

    @Override
    public void doTag() throws JspException, IOException {
        JspFragment jf = this.getJspBody();
        StringWriter sw = new StringWriter();//得到一个输出流
        jf.invoke(sw);//注意:要想修改标签体内容个必须先执行标签体
        //得到标签体内容
        String content = sw.getBuffer().toString();
        content = content.toUpperCase();//将标签体中的字符串变为大写
        
        PageContext pageContext = (PageContext) this.getJspContext();
        pageContext.getOut().write(content);//输出
        
    }
}

3.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/simpleitcast" prefix="itcast"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>使用简单标签修改标签体内容</title>
  </head>
  <body>
    <itcast:demo3>
    aaa
    </itcast:demo3>
  </body>
</html>

说明:这里执行是先让标签体执行,然后让内容输出到我们自己定义的一个流中,然后我们从流中拿到数据,修改之后再输出给浏览器。

例:控制余下jsp页面是否执行
simpletag.tld

    <tag>
        <name>demo4</name>
        <tag-class>cn.itcast.web.simpletag.SimpleTagDemo4</tag-class>
        <body-content>scriptless</body-content>
    </tag>

SimpleTagDemo4

package cn.itcast.web.simpletag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//控制标签体之后余下页面是否执行
public class SimpleTagDemo4 extends SimpleTagSupport{

    @Override
    public void doTag() throws JspException, IOException {
        //只要此方法抛出这个异常,那么余下的页面将不会执行
        throw new SkipPageException();
    }
}

4.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/simpleitcast" prefix="itcast"%>
<itcast:demo4/>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>控制余下标签体不再执行</title>
  </head>
  <body>
    aaa
  </body>
</html>

可以看到此功能很容易实现。

5.开发带属性的标签

  • 要想让一个自定义标签具有属性,通常要完成两个任务:
    在标签处理器中编写每个属性对应的setter方法
    在tld文件中描述标签的属性
  • 为自定义标签定义属性时,每个属性都必须按照javaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收jsp页面调用自定义标签时传递进来的属性值。例如,属性url,在标签处理器类中就要定义相应的setUrl(String url)方法。
  • 在标签处理器中定义相应的set方法后,jsp引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用set属性方法为标签设置属性。

例:通过属性控制标签体执行的次数
simpletag.tld

    <tag>
        <name>demo5</name>
        <tag-class>cn.itcast.web.simpletag.SimpleTagDemo5</tag-class>
        <body-content>scriptless</body-content>
        <attribute>
            <name>count</name>
            <required>true</required><!-- 这表示此属性是必须的 -->
            <!-- 此属性是否是一个运行时表达式,若为false则只能是静态的值,一般都是true -->
            <rtexprvalue>true</rtexprvalue>
            <type>java.lang.Integer</type><!-- 这个属性是规定参数的java属性,如果不正确则报错 -->
        </attribute>
    </tag>

SimpleTagDemo5

package cn.itcast.web.simpletag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//通过属性控制标签体的执行
public class SimpleTagDemo5 extends SimpleTagSupport{
    //这里注意:我们顶一个的是一个int类型的,但是标签中我们使用的是字符串类型,
    //这里引擎帮我们进行了转换,但是只支持八种基本类型的转换
    private int count;
    public void setCount(int count ){
        this.count = count;
    }

    @Override
    public void doTag() throws JspException, IOException {
        for(int i = 0; i < count; i++){
            this.getJspBody().invoke(null);
        }
    }
}

5.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/simpleitcast" prefix="itcast"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>通过属性控制标签体执行次数</title>
  </head>
  <body>
    <!-- 如果在配置文件中rtexprvalue为true,则这里可以是一个表达式 -->
    <itcast:demo5 count="5">
    xxx
    </itcast:demo5>
  </body>
</html>

**注意:引擎只能转换八种基本类型数据,而不能转换复杂类型数据,如日期类型。但入股我们一定要传入复杂类型的话一般有两种方式:

      <%
        Data date = new Date();
        request.setAttribute("date", date);
     %>
     <itcast:demo6 date="${date}">
     xxx
     </itcast:demo6>

或者:

    <itcast:demo6 date="<%=date %>">
    xxx
    </itcast:demo6>

最后我们给出属性配置中的一些标签:

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

推荐阅读更多精彩内容

  • 1.什么是JSP (1)jsp全称是Java Server Pages,它和Servlet技术一样都是sun公司定...
    yjaal阅读 3,577评论 5 99
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,296评论 18 399
  • 一、JSP基础 1.1什么是JSP JSP(Java ServerPage)是Java服务器端动态页面技术。是su...
    晨星资源阅读 1,101评论 0 6
  • 主要内容: 防盗链 开发if标签 开发if else标签 开发foreach标签 开发HTML转义的标签 打包标签...
    yjaal阅读 696评论 0 0
  • 三更夜闯归家路,履间落地碎土音, 树遮月破照裂云,轻扣听蝈哼待应。 垂头无端嘴生风,唇开红漫满舌腥, 门扉小隙黑无...
    葡萄美酒阅读 132评论 0 0