zoukankan      html  css  js  c++  java
  • Servlet 之jsp(上)

      jsp与Servlet本质都是一样的。jsp是在html中嵌入java代码,servlet是在java代码中嵌入html。

      tomcat在获得jsp页面后,在work目录下,会将其转换为servlet的java文件(如hello.jsp--->hello_jsp.java),而后对其进行编译,这里分析jsp各个部分功能的时候,注意它转为servlet中的代码结构。hello_jsp.hava中的_jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)方法相当于Servlet中的service(javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)。

    --------------------------------------------------------------------------------------------------->

      JSP脚本元素 

      表达式: <%= 表达式 %> 将表达式结果输出到浏览器,底层解析后 out.print(表达式);
      代码片段: <% java 代码 %> 将“java代码”完整复制到service方法体中。 service(){ java代码片段}
      脚本声明: <%! 声明内容 %> 将“声明内容”完整复制到class类体中, class hello { 脚本声明 }

    <body>
        Hello again!
        <br>
        <%=i%>
        <% int i = 5; %>
        <%=i%>
        <%! int i = 10; %>
        <% i++; %>
        <%=this.i%>
    </body>

    这里<%! %>属于声明,所以其中i=10为hello_jsp.java代码中的成员变量,而<% int i = 5 ;%>会被直接搬到_jspService(httpServletRequest, httpServletResponse)方法体中,所以属于局部变量,而<%= %>中的内容会在搬到方法体中用out.print()进行输出。

    --------------------------------------------------------------------------------------------------->

      jsp中的注释分<%-- --%>,注释部分的内容到java源码中就不存在了。

    --------------------------------------------------------------------------------------------------->

      JSP指令

      jsp在web容器中被转为servlet,文件编码、依赖类、发送给浏览器输出编码、行为等等需要jsp页面与tomcat进行约定,这个依据就是jsp指令。指令的格式为:<%@指令名称  属性=值 属性=值  .....%>,指令有三,page, include, taglib。

      <%@page  属性=值 属性=值  .....%>

    >使用
    * 一个指令可以编写多个属性
    * 相同指令可以使用多次
    * 指令可以使用在任意位置
    * 大部分属性只能使用一次,否则jsp将抛出异常。之后少数可以重复使用。例如:import

      >编码

    pageEncoding :当前页面的编码
    contentType:jsp生成servlet响应给浏览器编码
    注意:一般一致
    对比:
    如果只有pageEncoding,设置当前编码,也可以设置响应编码
    如果只有contentType,可以设置响应编码,也可以设置当前页面编码

      >缓存机制

    buffer : 设置缓存大小,默认:8kb
    autoFlush : 缓存如果溢出,将自动刷新,常设置为true,设置false有可能异常:java.io.IOException: Error: JSP Buffer overflow

      >常用

    session : 表示当前jsp页面是否可以使用session 内置对象。 true:可以使用 jsp脚本(表达式、代码块)中 使用 session
    import : jsp使用其他类,进行导包。 分别导入:java.util.List 一次性导入:java.util.List,java.util.ArrayList 星号:java.util.*
    language :表示jsp支持嵌入语言(java)
    info ,使用在servlet接口第5个方法,getServletInfo()

      >错误处理机制

      在每个展示页面中都设置<%@ page errorPage="error.jsp"%>,当页面出现错误时,会跳转到该jsp页面,在error.jsp中设置<%@ page isErrorPage="true" %> 就可以引用exception对象,获取到错误的原因,可以灵活处理它的内容,像<%=exception.getMessage()%>。当页面出现错误时,Chrome浏览器进行访问,可以看到它会把错误原因,以及页面内容都输出到浏览器上。但ie浏览器会出现下图显示,原因是此时服务器响应的状态码为500,ie浏览器将会给出自己的错误页面,可以利用过滤器对其进行处理。

      一般来说,我们会对其进行页面的统一配置,给整个工程进行友好错误页面。在web.xml中配置如下:

    ......
        <error-page>
            <exception-type></exception-type>
            <location></location>
        </error-page>
    </web-app>

    看error-page的说明,可以发现,这个标签需要两个内容,错误定义和位置,而错误定义又分两种:

    Element : error-page
    The error-page element contains a mapping between an error code or exception type to the 
     path of a resource in the web application Used in: web-app
    
    Content Model : ((error-code | exception-type), location)

    这几个参数的内容分别为((错误码(状态码)|java异常类型),友好页面位置)。

      taglib指令之后专门汇总

      这里再总结一下<%@ include %>指令的用法与场景。

      在很多门户网站中,往往一个页面会被切成很多块儿,不同的开发人员会对不同的快分别进行处理,但整个网页也会有很多公共资源,例如框架,各种链接等等,同样的版面和内容会被放到很多独立的子模块中使用,如果子模块中处理这些公共内容,无疑工程量巨大,而且容易出错,不易扩展,所以我们会将其做成单独的界面,而后在每个需要的子模块中引用该界面。就相当于这个界面会与子模块的界面合并,所以这个指令主要就是做合并的工作。

      这里的合并分为两种,一种静态包含<%@include  file="" %>,另一种是动态包含<jsp:include page="">。前者的过程是A.jsp包含B.jsp,tomcat将A和Bjsp合并在一起,生成一个A_jsp.java文件,然后编译,最后运行,其结果为:AB合并(一个servlet),所以两个页面中处理变量时需要注意;后者的过程是A.jsp 包含 B.jsp ,tomcat将A生成 A_jsp.java文件,将B生成B_jsp.java文件,分别编译,在运行时将内容合并输出。结果:AB合并(两个servlet)。

    --------------------------------------------------------------------------------------------------->

      JSP内置对象

      所谓的内置对象,即可以直接在<%= %>与<% %>中可以直接使用的变量,即_jspService(httpServletRequest, httpServletResponse)中提供的变量,看代码:

      public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
            throws java.io.IOException, javax.servlet.ServletException {
    
        final javax.servlet.jsp.PageContext pageContext;
        javax.servlet.http.HttpSession session = null;
        java.lang.Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);
        if (exception != null) {
          response.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
        final javax.servlet.ServletContext application;
        final javax.servlet.ServletConfig config;
        javax.servlet.jsp.JspWriter out = null;
        final java.lang.Object page = this;
        javax.servlet.jsp.JspWriter _jspx_out = null;
        javax.servlet.jsp.PageContext _jspx_page_context = null;
    
      ......

    page 表示当前页,this引用。
    config 表示 servlet配置,类型:ServletConfig
    application 表示 web 应用上下文,类型:ServletContext

    request 表示一次请求,类型:HttpServletRequest
    response 表示一次响应:类型:HttpServletResponse

    session 表示一次会话,类型HttpSession
    out 表示输出响应体,类型JspWriter

    exception 表示发生异常,类型 Throwable
    pageContext 表示 jsp页面上下文(jsp管理者) 类型:PageContext

      其中,page 指代当前页面(一个页);request,一次请求(默认就一个页,如果使用请求转发可以多个页面);session,一次会话(可以有多次请求);application,一个应用(可以多次会话)。这里主要查看JspWriter与pageContext。我们将out对象打印出来,可知:

    org.apache.jasper.runtime.JspWriterImpl@2df7783d

    到tomcat中找到源码,查看该方法中的write(),最后查看到initOut():

        private void initOut() throws IOException {
            if (out == null) {
                out = response.getWriter();
            }
        }

    所以这里底层使用了response.getWriter()获取out对象,在之前的servlet中已经解释过该方法的详细用法,这里略过。

      另外,有个缓存的问题。看页面中的代码:

    ......
        <br>
        <%= out %>
        <%
            out.print("111");
            out.print("2222");
            response.getWriter().print("3333");
        %>
    </body>

    这块代码会直接放入到hello_jap.java中然后统一在页面按照代码逻辑输出,但实际上,我们看页面源码:

    3333
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        Hello again!
        <br>
        10
        
        5
        
        
        10
        <br>
        org.apache.jasper.runtime.JspWriterImpl@4d6f119e
        1112222
    </body>
    
    </html>

    request.getWriter().print()中的内容被放到了页面最前面。原因在于,jsp与servlet缓存并不一致(JspWriter<->response.getWriter()),各自有各自的缓存,out的内容会首先被放到jsp缓存中,而request.getWriter()输出在servlet缓存里,等到最后,servlet会将自己缓存与jsp缓存内容结合输出到页面,造成上述情况。知道了这个原理,我们就可以当jsp将request.getWriter()之前所有内容刷到缓存中时,用out.flush()将jsp缓存中的内容刷新到servlet缓存中,而后再直接向servlet中存放3333,再输出就是代码逻辑顺序的展示了。

    ......
        <br>
        <%= out %>
        <%
            out.print("111");
            out.print("2222");
            out.flush();
            response.getWriter().print("3333");
        %>
    </body>

      pageContext是jsp页面的管理者,可以用getXXX()获得其它8个对象的引用;可以对指定作用域属性的值进行快捷操作:

    默认作用域属性进行操作:page
        getAttribute(name)  获得 page作用域数据
        setAttribute(name ,value )    给page作用域设置内容
        removeAttribute(name )  移除所有作用域的内容(page/request/session/application)
    指定作用域
        getAttribute(name ,scope)  获得 指定作用域数据
        setAttribute(name ,value ,scope )    给指定作用域设置内容
        removeAttribute(name ,scope)  移除指定作用域的内容(page/request/session/application)
    提供作用域常量
        PageContext.PAGE_SCOPE  page
        PageContext.REQUEST_SCOPE  request
        PageContext.SESSION_SCOPE  session
        PageContext.APPLICATION_SCOPE  application

    --------------------------------------------------------------------------------------------------->

      JSP内置动作标签(可以取代JSP脚本,格式为<jsp:标签名 />)

      这里给出实际场景中的代码,看懂即可:

    <jsp:include page="" />  动态包含
    <jsp:forward />  转发
        <jsp:param/>  处理请求参数的 , 可以将中文内容进行 URL编码,类似  <form enctype="application/x-www-form-urlencoded">
    
    
    <jsp:include page="/error.jsp">
        <jsp:param value="uservalue" name="username"/>
    </jsp:include>
    
    <jsp:useBean id="user" class="com.itheima.User"></jsp:useBean>  
    <%-- User user = new User();  pageContext.setAttribute("user",user)--%>
    
    <jsp:setProperty property="username" name="user" value="jack"/>
    <%--  user.setUsername("jack") --%>
    
    <jsp:getProperty property="username" name="user"/>
    <%-- user.getUsername() --%>
  • 相关阅读:
    新代(Syntec)机床的IP设置
    使用任务计划程序实现用户未登录情况下的程序开机自启动
    sql server 数据库访问端口配置
    Http请求
    EF
    SQL Server常用处理
    利用ZXing生成条码二维码例子
    SQL JOIN常见情况
    C#ORM框架收集
    sql server连接oracle并实现增删改查
  • 原文地址:https://www.cnblogs.com/bruceChan0018/p/5899429.html
Copyright © 2011-2022 走看看