zoukankan      html  css  js  c++  java
  • 【javaWEB】jsp相关

    1.什么是jsp(java server page)

    它和servlet一样都是SUN推出的用于开发动态web资源的一种技术。JSP本质上也是一个servlet。我们暂时可以理解为JSP就是HTML+一些java代码。

    2.JSP的原理

    .jsp文件(比如index.jsp)会被先翻译(转译)成java文件(对应的名字叫做index_jsp.java),然后再被编译成.class文件(index_jsp.class)。

    我们最终执行的是.class文件。

    也就是说其实服务器会帮我们生成2个文件(一个是java文件一个是class文件),然后我们执行class文件。

    如果我们在服务器上把对应的java文件删除掉,但保留class文件,那么再次访问的时候就不会生成java文件,因为它发现class文件还在,就直接访问了。

    但是如果我们的jsp文件内容修改过了,那么服务器就会帮我们自动生成对应的java文件和class文件。

    3、我们之前说过jsp本质上就是一个servlet类,这话怎么理解?我们打开服务器帮我们生成的index_jsp.java文件,发现这个类继承了org.apache.jasper.runtime.HttpJspBase

    ==> public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent

    ==> public abstract class HttpJspBase extends HttpServlet implements HttpJspPage

    -->打开发现这个类是继承了HttpServlet ,所以可以说我们的jsp文件生成的对应的java类其实本质上是继承自HttpServlet的孙子类,所以本质上是一个servlet。

    ——HttpJspBase文件里面其实是覆写了父类的service等方法,但是它还留了一个心眼,就是在覆写的方法里面调用了自己写的对应的抽象方法,比如_jspService

    所以我们子类只需要实现它的抽象方法即可。

    @Override public final void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        _jspService(request, response);

      }

    4、那服务器是怎么把jsp里面的html代码输出到浏览器去的?我们打开index_jsp.java,查看里面的_jspService,发现,所有的html代码被它原封不动的用out.write()方法都输出去了。

    ——而服务器又是怎么处理jsp里面的那些java代码的呢?同样的我们在index_jsp.java里面查看_jspService,发现java代码是直接被执行的,没什么弯弯肠子。

    5、JSP和Servlet的分工:

    ——Servlet一般用于获取表单数据、处理业务逻辑、分发转向。

    ——JSP重点在于在模板基础上利用一些对象显示数据。

    6、JSP三大指令之一——page。

    ——指令的统一写法都是:

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

    ——这个pageEncoding相当于我们之前的:

    response.setContentType("text/html;chaeset=***");

    8、三大指令之include。就是包含的意思,这个包含是把另一个页面的文件内容全部先包含进来,生成一个jsp文件,然后对这个总的jsp文件进行翻译成java编译成class文件,所以我们在服务器中也只看到当前文件的java和class文件,而看不到那个被包含进来的文件的java和class文件(因为都在一起了)。

    <%@ include file="/login.jsp" %>

    ——上面这种包含文件的方式静态方式,当然还有一种动态方式,如下。动态方式其实当前文件和被包含的文件就会各自生成各自的java和class文件。

    <jsp:include page="/login.jsp"></jsp:include>

    ——include使用原则:尽量使用静态方式。但是我们发现一个问题,就是我们使用静态方式的时候,打开那么合并之后生成的java文件,发现另一个文件的那些html里的Prologue和Head中的内容都被out.write重复输出了。解决办法就是删除当前文件的尾部html闭合标签,删除被包含文件的头部标签,这样一个保留开头的部分一个保留结尾的部分,组成一个文件后,不冗余了。

    9、jsp6大动作。

    ——先来3个。下面这两种做法的效果是一样的,我们就可以对照着看出那3个jsp动作分别对应着创建一个对象、设置属性值、获取属性值。我们可以看到在第一行帮我们使用page的import属性引入了Student类。

        <%
            Student stu1=new Student();
            stu1.setName("andy");
            out.write(stu1.getName());
         %>
    
         <jsp:useBean id="stu2" class="com.hello.entity.Student"></jsp:useBean>
         <jsp:setProperty property="name" name="stu2" value="eric"/>
         <jsp:getProperty property="name" name="stu2"/>

    ——下面2种写法也是相同的,一种是java代码,另一种就是jsp特有的动作,转发、携带参数

    <% request.getRequestDispatcher("/777.jsp?username=andy&password=1234").forward(request, response); %>

    <jsp:forward page="/777.jsp">

    <jsp:param value="andy" name="username"/>

    <jsp:param value="1234" name="password"/>

    </jsp:forward>

    然后,我们可以在777.jsp的页面来接受这个参数,使用表达式的写法是:

         <%=request.getParameter("username") %>
         <%=request.getParameter("password") %>

    10、JSP的9大对象。9大对象,我们就可以理解为可以直接在<%%>和<%=%>中直接使用的对象。包括request、response、session、exception、application、out、page、pageContext、config。其中4大域对象是request、session、application和pageContext。

    ——以下是在1.jsp文件中:

    <%
        // page,只在当前页面有效,其他页面无法取到这个值
        pageContext.setAttribute("name", "page", pageContext.PAGE_SCOPE);
    
        // request只对一次请求有效,要在其他页面有效的话就需要转发,重定向算是2次请求就无法取值了
        // 以下两种是等价的
        request.setAttribute("name", "request");
        pageContext.setAttribute("name", "request", pageContext.REQUEST_SCOPE);
    
        // 针对一次会话有效
        session.setAttribute("name", "session");
        pageContext.setAttribute("name", "session", pageContext.SESSION_SCOPE);
    
        // 整个程序都有效,本质上是一个servletContext
        application.setAttribute("name", "application");
        pageContext.setAttribute("name", "application", pageContext.APPLICATION_SCOPE);
        request.getRequestDispatcher("2.jsp").forward(request, response);
        // 与上面等价
        // pageContext.forward("2.jsp");
    %>

    ——以下是在2.jsp文件中:
        <!-- 下面的是等价的 -->
        <%=request.getAttribute("name") %>
        <%=pageContext.getAttribute("name", pageContext.REQUEST_SCOPE) %>
    
        <!-- 真正强大的函数 -->
        <%=pageContext.findAttribute("name") %>

    ——以上的输出结果都是:

    request request request

    ——需要注意的是:

    1. pageContext作为四大域对象之一,它可以操作其他三个域对象,但它自己的作用于其实很窄,仅仅针对当前页面有效,所以用的较少。
    2. 但我们需要用request、session等的时候一般就直接用,很少利用pageContext来操作,因为毕竟少一些代码。那么pageContext真正强大的函数其实是findAttribute,它可以依次从page、request、session、application去找,找到了就停止了,所以上面的例子在请求转发中输出是request,如果我们改为重定向的话,那么findAttribute的结果就是session,不继续向application找了。
    3. request实际开发中用的比较多,用来登录注册跳转等等。
    4. session用的也比较多,不仅可以存放用户对象,还可以实现购物车等功能。
    5. application因为作用域比较强大,开发中慎用。

    11、EL表达式(expression language)。它是一种获取数据的规范,主要目的就是用来简化java代码的,如下面的例子。但本质上用的pageContext的findAttribute方法先找到属性名为s的对象,然后再取对象里的属性值。也就是说${s}相当于pageContext.findAttribute("s")

        <%
            Student stu=(Student)request.getAttribute("s");
            out.write(stu.getName());
         %>
         <!-- 和上面那种做法是等价的 -->
         ${s.name }

    ——另一个需要注意的是EL表达式的容错能力比较强。比如上述代码中如果我们把s随便换成一个我们未定义的属性。那么上面一种写法中stu就是null值,这一步不会报错,但是下一步相当于null.getName()就会报错NullPointerException。但是EL表达式不会报错,它会把取到的null值自动转化成空字符串。

    ——表达式的属性导航,也就是链式属性,本质上是一个类中包含了另一个,然后链式调用。

    ${s.city.address}

    ——[]比点.强大,强大之处主要体现在对键值对或对象之外的取值,因为点.是根据属性名(或key的名字)字来的,如果没有名字就很难取值,比如针对List只有序列下标,可以用下面来根据序号取值。

    ${l[1]}

    ——EL表达式会把空字符串和没有内容的集合都当成null值,而empty就是判断是否null的函数,如果是就返回true。所以下面代码的结果是“true true false true false”。

        <%
            String str1=null;
            request.setAttribute("str1", str1);
    
            String str2="";
            request.setAttribute("str2", str2);
    
            String str3="hello";
            request.setAttribute("str3", str3);
    
            List list1=new ArrayList();
            request.setAttribute("list1", list1);
    
            List list2=new ArrayList();
            list2.add("hi");
            request.setAttribute("list2", list2);
         %>
    
         ${empty str1 }
         ${empty str2 }
         ${empty str3 }
         ${empty list1 }
         ${empty list2 }

    ——EL表达式还支持三目运算符。比如我们从数据库中取得某个数据,然后根据这个数据显示不同的状态等等:

    12、EL的11个隐式对象。

    ——先来4个。分别是pageScope、requestScope、sessionScope和applicationScope。它们的用法就是:我们之前说直接使用${s}其实执行的是pageContext.findAttribute方法从page一直找到application找到就停止,那么会存在一种情况就是我们如果只想要session的或者application的,但它就在request就找到停止了,怎么办?解决办法就是我们上面的四个隐式对象,用法如下,就是只找session中的s属性:

    ${sessionScope.s}

    ——param和paramValues是针对表单数据的,底层代码相当于request.getParameterrequest.getParameterValues。用法如下:

    ${param.username}
    ${paramValues.hobby[1]}

    ——header相当于之前的request.getHeader()。用法如下。initParam就是获取配置信息的,用法雷同:

    ${header.User-Agent}

    ——还有一个cookie,用法如下:

    ${cookie.JSESSIONID.value}

    ——最后一个pageContext。它是一个对象,对应着JSP的内置对象pageContext。而其余10个隐式对象都是一个Map集合。这也就意味着其余10个Map集合只能通过获取key值进行数据获取,而不能使用什么特殊的方法。但是pageContext可以通过一些方法来获取,而且我们说过pageContext可以操作JSP的其他对象,所以它再次显示出它的无所不能了。比如最原始的写法是如下:

    <form method="post" action="/servlet/Day01_JSP/login.jsp">
    </form>

    我们可以通过java代码这样写,因为request是内置的对象:
    <form method="post" action="<%=request.getContextpath() %>/login.jsp">
    </form>

    但是我们说在EL表达式里面的11个隐式对象里没有request,所以自然不能调用getContextpath,而requestScope是个Map集合,自然也不能调用什么方法。所以这个时候就需要pageContext了,如下:

    <form method="post" action="${pageContext.request.contextPath}/login.jsp"></form>

    13、JSTL(JSP Standard Tag Library)JSP标准标签库。因为我们的EL表达式只能处理比较简单的输出计算,对判断、循环等就无能为力,这就是JSTL存在的意义了。

    ——我们需要导入jstl库。我们在创建一个Web Project的时候,如果选择java ee 5.0版本以上的话,那么自动就有jstl-1.2.jar包,在这个jar包里有我们的核心库,我们引入进来后,就可以在页面使用了。如果我们创建项目的时候用的是java ee 4.0或更早版本,那么下面会出现一个选项可以让我们添加进jstl的jar包。

    <!-- c相当于别名 -->
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

    ——我们先来3个通用标签,输出结果是“eric eric andy”。

        <c:set var="name" value="eric" scope="session"></c:set>
        <!-- 下面两句是等价的,可见在基础的输出方面,还是EL表达式方便  -->
        <c:out value="${name}"></c:out>
        ${name}
        <c:remove var="name"/>
        <c:out value="${name }" default="andy"></c:out>

    ——条件标签if choose。输出结果是“我是5大,还3粗呢 我是10”。需要注意的是if标签没有对应的else,只能再写一个if。还有choose就相当于我们常用的switch。

        <c:if test="${5>3 }">我是5大,还3粗呢</c:if>
        <c:if test="${3>5 }">我是3大</c:if>
    
        <c:set var="num" value="${10 }"></c:set>
        <c:choose>
            <c:when test="${num==0 }">我是0</c:when>
            <c:when test="${num==5 }">我是5</c:when>
            <c:when test="${num==10 }">我是10</c:when>
            <c:otherwise>我什么都不是</c:otherwise>
        </c:choose>
    • 1

    ——强大的foreach循环。有好几种用法,先来第一种:

    <c:forEach var="i" begin="0" end="5" step="1">${i }<br/></c:forEach>

    结果就是:

    
    

    再来第一种,就是我们常用的如果遍历一个Map集合或者数组的话:

        <%
            List list=new ArrayList();
            list.add("111");
            list.add("222");
            list.add("333");
            request.setAttribute("list", list);
         %>
        <c:forEach items="${list }" var="l">${l }<br/></c:forEach>

    输出结果就是:

    111
    222
    333

    还有一个varStatus,里面存储了循环的一些属性,比如索性,计数,是否首个末个等。我们结合table的例子来说明:

        <table border="1">
            <tr>
                <td>数据</td>
                <td>索引</td>
                <td>计数</td>
                <td>是否循环的第一个</td>
                <td>是否循环的最后一个</td>
            </tr>
            <c:forEach items="${list }" var="l" varStatus="vs">
                <tr style=" outline: 0px; word-break: break-all; color: rgb(0, 153, 0);">red" :"gray"}">
                    <td>${l }</td>
                    <td>${vs.index }</td>
                    <td>${vs.count }</td>
                    <td>${vs.first }</td>
                    <td>${vs.last }</td>
                </tr>
            </c:forEach>
        </table>

    结果是: 

    14、补充知识点。

    ——jsp里面有一种声明。用来声明全局成员和静态块。模板是<%! %>

  • 相关阅读:
    MFC添加右键菜单
    人生导师——如何学习C++的Windows方向
    删除CListCtrl中具有某一相同数据的所有行
    向某地址写入值并执行
    问题解决——使用CriticalSection后 0xXXXXXXXX处最可能的异常: 0xC0000005: 写入位置 0x00000014 时发生访问冲突
    问题解决——Win7 64 安装 AutoCAD 2010 32位 和 清华天河PC CAD
    问题解决——在结构体中使用set保存结构体数据
    问题解决——基于MSCOMM32.OCX控件的类在客户机不能创建控件
    问题解决——ShowWindow不显示窗口
    问题解决——cout 输出 CString
  • 原文地址:https://www.cnblogs.com/vmkash/p/9052002.html
Copyright © 2011-2022 走看看