JSP基础学习笔记All In One

🎉参考视频教程https://www.bilibili.com/video/BV1kb411h7Aa

🎉个人网站http://qkmango.cn

JSP初步

JSP是什么?

  1. JavaServer Pages

  2. 基于Java语言实现的服务器端页面

  3. JSP是javaEE规范之一

JSP文件通常放到什么位置?

  1. JSP可以放到WEB-INF目录外,目前我们是这样做的

  2. 在实际开发中,有很多项目是将JSP放到WEB-INF目录中,保护JSP

  3. WEB-INF目录中的数据时相对安全的

JSP文件后缀是什么?

  1. 默认是.jsp
  2. 但是JSP文件的后缀也可以修改的,通过修改CATALINA_HOME/conf/web.xml文件

JS和JSP的区别

  1. JS:JavaScript,运行在浏览器中,和服务器没有任何关系,和Java也没有关系
  2. JSP:JavaServer Pages,运行在服务器中,JSP底层就是Java程序,运行在JVM中

JS和JSP就相当于雷锋和雷峰塔的关系,JS和JSP没有任何关系

JSP的执行原理

  1. 浏览器上访问的路径,虽然是以.jsp结尾,访问的是某个jsp文件,其实底层执行的是jsp对应的Java程序
  2. Tomcat服务器负责将.jsp文件翻译生成.java源文件,并且将Java源文件编译生成.class字节码文件
  3. 访问jsp,其实底层还是执行力.class文件
  4. Tomcat服务器内置了一个jsp翻译引擎,专门负责翻译jsp文件,编译Java源文件
  5. index.jsp会被翻译生成index_jsp.java,编译生成index_jsp.class
  6. index_jsp这个类继承了HttpJspBase,而HttpJspBase继承了HttpServlet
  7. 所以jsp就是Servlet,只不过jsp的强项是做动态页面展示
  8. 在JSP文件中编写的所有的HTML、CSS、JavaScript,对于JSP来说,只是不同的字符串,会被翻译到Servlet的service()方法的out.write(“翻译到这里”);方法中

JSP文件第一次访问时为什么非常慢?

  1. 启动JSP翻译引擎
  2. 需要一个翻译过程
  3. 需要一个编译过程
  4. 需要Servlet对象的创建过程
  5. init()方法调用
  6. service()方法调用…

为什么第二次以上方位JSP为什么快?

  • 因为不需要重新翻译

  • 不需要重新编译

  • 不需要创建Servlet对象

  • 直接调用Servlet对象的service()方法

JSP什么时候会被重新翻译为Java源文件

当JSP文件被修改后,会被重新翻译和编译

什么确定jsp文件被修改了呢?服务器会将记录的文件最后修改时间和文件的修改时间对比,最后修改时间不同说明被修改,然后重新翻译和编译JSP文件

JSP注释

<%----%>这是jsp的专业注释,使用这种注释方式,不会被翻译到Java源文件中

<%-- JSP注释 --%>

JSP小脚本scriptlet<%%>(webapp02)

JSP小脚本中的代码会被翻译到Servlet的service()方法中

<%
	Java语句;
	Java语句;
    Java语句;
    Java语句;
    Java语句;
%>
  1. 小脚本中的Java语句会被翻译到Servlet的service()方法中,所以小脚本中必须编写Java语句
  2. 所谓的JSP规范,就是SUN制定好的一些翻译规则,按照翻译规则进行翻译,生成对应的Java源程序。不同的web服务器翻译的结果完全是相同的,因为都遵守了JSP翻译规范
  3. 小脚本的数量随意,可以多个
  4. 小脚本中编写Java程序出现在service()方法中,service()方法的代码是有执行顺序的,所以小脚本中的程序也是有顺序的
  • 例如以下JSP会被翻译为:

JSP文件

<%
    int i = 10;
%>
<html>
    <%
        System.out.println(i);
    %>
    <head>
        <%
            double d = 3.0;
        %>
        <title>JSP</title>
        <%
            System.out.println(d + i);
        %>
    </head>
    <body>
        hello jsp!
        <%
            System.out.println(d * i);
            System.out.println(d / i);
        %>
    </body>
</html>
<%
    String name = "king";
    System.out.println("name = " + name);
%>

翻译为的Java源文件Servlet的service()方法中

public void _jspService(final HttpServletRequest request, 
                        final HttpServletResponse response)
        throws java.io.IOException, javax.servlet.ServletException {

    int i = 10;
    out.write("<html>");
    System.out.println(i);
    out.write("<head>");
    double d = 3.0;
    out.write("<title>JSP</title>");
    System.out.println(d + i);

    out.write("</head>");
    out.write("<body>");
    out.write("hello jsp!");

    System.out.println(d * i);
    System.out.println(d / i);

    out.write("</body>");
    out.write("</html>");

    String name = "king";
    System.out.println("name = " + name);
}

控制台结果

10
13.0
30.0
0.3
name = king

网页显示

hello jsp!
  • 以下代码编译无法通过,因为service()方法中不能编写实例变量、方法、静态代码块
<%
	public String username;
%>
<%
	public void method(){
        
    }
%>
<%
	static {
        
    }
%>

JSP声明语法格式<%!%>(webapp03)

声明语法块会被翻译到Servlet的类体中,即service()方法外面

<%!
	实例变量;
	静态变量;
    方法;
  	静态代码块;
    构造函数;
    ......
%>
  1. 因为声明语法块会被翻译到Servlet的类体中,即service()方法外面,所以声明块中不能直接编写Java语句,除非是变量的声明;
  2. JSP声明语法块中的代码会按照先后顺序被翻译到Servlet类体中;

如下代码翻译情况:

jsp源文件

<%!
    int i = 10;
%>
<%
    System.out.println("i = " + i);
    method();
%>
<%!
    public void method() {
        System.out.println("method...");
    }
%>
<%!
    static {
        System.out.println("Class Loader");
    }
%>

翻译为的Java源文件

值得注意的是,虽然JSP源文件中调用method()方法看似在声明method()方法前,但是他们使用的一个是小脚本块,一个使用的是声明块,最终翻译成为的Java文件,声明块里面的method()方法的定义还是在前的,在类体里面

public class index_jsp extends HttpJspBase {
    int i = 10;
    public void method() {
        System.out.println("method...");
    }
    static {
        System.out.println("Class Loader");
    }
    
    public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
        
        System.out.println("i = " + i);
    	method();
}

JSP内置对象(webapp04)

JSP中有9大内置对象,都在service()方法中定义

pageContext对象的描述https://www.cnblogs.com/nickup/p/9004594.html

  1. 什么是内置对象?

    可以直接在JSP文件中拿来使用的引用

  2. 九大内置对象有哪些?

    内置对象名称		完整类名
    pageContext		javax.servlet.jsp.PageContext			页面范围
    request			javax.servlet.htpp.HttpServletRequest	请求范围
    session			javax.servlet.http.HttpSessio			会话范围
    application   	javax.servlet.ServletContext			应用范围
        
    config 			javax.servlet.ServletConfig				Servlet配置信息
    out				javax.servlet.jsp.JspWriter				标准输出流
    page    		java.lang.Object [page=this]			(很少用)
    exception		javax.servlet.jsp.JspException	异常引用,需要学习JSP的page指令的isErrorPage属性
    
  3. 以上内置对象只能在service()方法中直接使用,在其他方法中无法直接使用,可以间接使用

  4. 💡主要研究JSP中的四个作用域对象/范围对象

    pageContext < request < session < application

    1. pageContext:在同一个页面中共享数据,不能跨JSP页面
    2. request:在同一个请求中共享数据(使用请求转发)【使用较多】
    3. session:在同一个对话中共享数据【使用较多】
    4. application:在同一个应用中共享数据,只要服务器不关

🚩注意:JSP九大内置对象之page对象的误区

要注意的是,page对象虽然是this的引用,但是page的类型是java.lang.Object,所以是无法通过page调用实例变量、方法等等,只能调用Object类型的一些方法

众所周知JSP内置的page对象是this的引用,在经过访问翻译为Java源代码后可以看到

final java.lang.Object page = this;,page正是这个Servlet对象的引用,既然是这样,那么就有了一下我写的JSP代码:

<%!
    int i = 10;
%>
<%
    System.out.println(page.i);
    System.out.println(this.i);
%>

首先我使用声明块声明了一个实例变量int i = 10,然后使用小脚本块通过page对象调用变量i,发现编辑器报错,我又试着直接使用this来调用,发现并没有报错;

这是候我已经很疑惑了,page = this,为什么this可以调用到i变量,而page调用不了呢?

于是将JSP文件进行了翻译为Java源文件,简化代码如下:

public final class index_jsp  {

    int i = 10;

    public void service(HttpServletRequest request, HttpServletResponse response)
        throws Exception{
        final java.lang.Object page = this;
        System.out.println(page.i);
        System.out.println(this.i);
    }
}

看到翻译后的Java源文件,绝对也并没有错误啊,先是声明了一个实例变量int i = 10;然后再service()方法中调用,page = this,为什么还是this可以调用实例变量i,而page无法调用实例变量i呢?

我又仔细看了一下代码,果然发现了问题所在,虽然page = this,但是page的类型是Object,即page只能调用Object类型的一些方法!

JSP表达式<%=%>(webapp05)

<%= %>等同于out.print();

  1. 表达式语法具有输出功能,输出到浏览器
<%!
    int i = 10;
%>

<!--使用out输出和使用表达式语法输出相同的内容-->
<%
    out.print("i = " + i);
%>
<%="i = " + i%>
  1. JSP的Java代码块是可以进行拼接的

    🚩JSP中的Java代码不仅翻译为Java源文件后有先后的顺序,而且可以按照顺序进行拼接的;

    如下的for循环为了动态输出h1~h6标题,将for循环拆分为了3部分,第二部分使用表达式进行动态输出

    <%
        for (int i = 1; i <= 6; i++) {
    %>
    		<h <%=i%> >标题字</h <%=i%> >
    <%
        }
    %>
    

    翻译后的Java文件

    for (int i = 1; i <= 6; i++) {
        out.write("<h");
        out.print(i);
        out.write(">标题字</h");
        out.print(i);
        out.write(">");
    }
    

JSP指令<%@%>(webapp06)

了解指令

  1. 指令的作用,是指导JSP翻译引擎如何翻译JSP代码

  2. JSP中共用三个指令

    • page 页面指令
    • include 包含指令
    • taglib 标签库指令
  3. 指令的语法格式

    <%@指令名 属性名=属性值 属性名=属性值...... %>
    

page指令的常用属性

contentType pageEncoding import session

errorPage isErrorPage isELIgnored

  1. contentType 设置JSP的响应内容类型,同时在响应的内容类型后面也可以指定响应的字符编码方式

  2. pageEncoding设置JSP的响应字符编码方式

    <%@ page contentType="text/html" pageEncoding="UTF-8" %>
    //等同于
    <%@ page contentType="text/html;charset=UTF-8" %>
    //翻译成为Java文件中的代码
    response.setContentType("text/html;charset=UTF-8");
    
  3. import组织导入(导包)

    <%@ page import="java.util.Date" %>
    翻译为Java源文件为导包语句
    import java.util.Date;
    
  4. session设置当前JSP页面中是否可以直接使用session内置对象;不写则默认session=“true”

    //1. session="true"表示可以直接使用九大内置对象session对象;不存在则创建一个新的session对象
    JSP:	<%@ page session="true" %>
    Java:	javax.servlet.http.HttpSession session = null;
        	session = pageContext.getSession();
    
    //2. session="false"表示不能直接使用session对象,并不会实实例化并获取session对象
    JSP:    <%@ page session="false" %>
        
    //3. 当我们想要使用session对象,并且如果没有session对象则不创建,那么可以指定session="false";然后通过Java代码的方式获取session对象
    JSP:    <%@ page session="false" %>
        	<% HttpSession session = request.getSession(false); %>
    Java:   HttpSession session = request.getSession(false);
    
  5. errorPage错误页面

    当前JSP页面出错之后要跳转的页面路径,需要使用该属性指定

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%--指定当此JSP页面出错后跳转到errorPage.jsp页面--%>
    <%@ page errorPage="errorPage.jsp" %>
    <html>
    <head>
        <title>JSP</title>
    </head>
    <body>
    <%
        <%-- 制造空指针异常,此JSP出错,会自动转发到errorPage.jsp页面--%>
        String s = null;
        s.toString();
    %>
    </body>
    </html>
    
  6. isErrorPage是否是错误页面,不写默认为isErrorPage=“false”

    isErrorPage="false"表示内置对象exception无法使用

    isErrorPage=“true” 表示内置对象exception可以使用

    设置当前页面是否为错误页面,当后天出错时,为了前端用户的使用感受而设置了errorPage属性,出错时跳转到错误页面,但是后台的错误信息也不会被打印出来了,所以通过isErrorPage属性设置当前页面是否为错误页面,当isErrorPage="true"时,表示当前 页面是一个错误页面,进而可以直接使用exception内置对象打印错误信息

    <%@ page contentType="text/html;charset=UTF-8" %>
    <%--设置当前页面为错误页面--%>
    <%@ page isErrorPage="true" %>
    <html>
    <head>
        <title>error page</title>
    </head>
    <body>
        error page
    </body>
    </html>
    <%
    	<%--打印错误信息--%>
        exception.printStackTrace();
    %>
    
  7. isELIgnored是否忽略EL表达式

includ指令

仅有一个属性file

<%@include file="msg.jsp"%>

  1. a.jsp可以将b.jsp包含进来,当然资源不一定是jsp,可能是其他的资源

  2. include的作用:

    在网页中有一些主题框架,例如网页头、网页脚,这些都是固定不变的,我们可以将网页头、网页脚等固定不变的单独写到某个JSP文件中,在需要的时候使用include指令包含进来;

    优点:

    代码量少了,便于维护(修改一个文件既可以作用于所有页面)

  3. 在一个JSP中可以使用多个include指令

  4. include实现原理

    1. 编译期(翻译)即将文件包含进去,多个JSP文件一起翻译为一个Java源文件
    2. a.jsp包含b.jsp,底层共生成一个Java文件,一个class字节码文件,翻译期包含/编译期包含/静态联编
  5. 静态联编的时候,多个JSP可以共享一个局部变量和实例变量,因为最终翻译之后,局部变量都被翻译到service()方法中,实例变量都被翻译到类体中

JSP动作(webapp07)

JSP中有七大动作,下面着重学习forward转发动作和include包含动作,了解bean动作

forward转发动作

<jsp:forward page="index2.jsp"/>等同于Java代码

request.getRequestDispatcher("index2.jsp").forward(request,response);

<%--index.jsp--%>
<%
    // 向request范围中存数据
    request.setAttribute("username","admin");
%>
<%--forward转发动作,将请求转发到index2.jsp--%>
<jsp:forward page="/index2.jsp"/>


<%--index2.jsp--%>
<%--从request范围中取数据--%>
<%=request.getAttribute("username")%>

include包含动作

include包含是动态包含,动态联编

使用include包含动作可以将其他jsp等资源包含展示在一个jsp

了解include动作

  1. a.jsp包含b.jsp,底层分别生成两个Java源文件,两个class字节码文件
  2. 编译阶段并没有包含,编译阶段是两个独立的class字节码文件,生成两个Servlet
  3. 使用include动作属于运行阶段包含,实际上是在运行阶段a中的service()方法调用了b中的service()方法,达到了包含效果
  4. a.jsp包含b.jsp,若两个jsp文件中有重名变量,只能使用动态包含,因为两个Java源文件是相互独立的,其余都可以使用静态包含
  5. include动作完成动态包含,被成为动态联编

包含原理

如下代码,index.jsp文件中使用include动作包含了index2.jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <body>
    	<jsp:include page="index2.jsp"/>
    </body>
</html>

index.jsp和index2.jsp两个文件翻译为Java源文件是各自独立的index.java和index2.java;

在index.java的service()方法中有这么一行代码,说明是index的service()方法在包含的位置调用了index2,执行了index2的service()方法;

所以两个jsp翻译后的Java文件是相互独立的,所以变量是不能通用的;

public void service(HttpServletRequest request, HttpServletResponse response) {
		//.......
      org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "index2.jsp", out, false);
		//......

💡include指令与include动作区别

include指令<%@include file="index2.jsp"%>
include动作<jsp:include page="index2.jsp"/>

  1. 无论是include指令还是include动作,都可以将其他页面包含进来
  2. include指令是静态联编,如果a.jsp包含b.jsp,那么在翻译期就会将b翻译进来,最后翻译形成一个Java源文件,所以a.jsp和b.jsp中的变量等是可以共用的
  3. include动作是动态联编,如果a.jsp包含b.jsp,那么在翻译期,会生成两个相互独立的Java源文件, 只是在执行a的service()方法的时候,在包含b的位置调用了b而已,所以两个jsp中的变量是不通用的

所以如果两个JSP中有同名的变量,需要使用include动作(动态联编);如果需要共享变量,可以使用include指令(静态联编);多数情况下都是使用include指令(静态联编)

bean

通过动作的方式,创建对象,以及往对象中设置值和取值

共有三个动作:useBean、setProperty、getProperty

<jsp:useBean id="对象名" class="包名.类名"/>  				<%--创建对象--%>
<jsp:setProperty name="对象名" property="属性名" value="值"/> 	<%--调用set方法--%>
<jsp:getProperty name="对象名" property="属性名" />  		<%--调用get方法--%>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值