1,JSP的4种基本语法
1.1,JSP注释
JSP注释用于标注程序开发过程中的开发提示,不会输出到客户端(用户无法通过检查源代码而看到注释)。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <div> <%--我是JSP注释--%> <!--我是HTML注释--> </div> </body> </html>
1.2,JSP声明
<%!%>称作声明,其中写的内容将来会直接翻译在Servlet类中,因为我们可以在类中定义方法和属性以及全局变量,所以我们可以在<%!%>中声明方法、属性、全局变量
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Test</title> </head> <body> <div> <%! public int count; public String info() { return "hello"; } %> <% out.println(count++); out.println(info()); %> </div> </body> </html>
由于JSP声明语法定义的变量和方法对应于Servlet类的成员变量和方法,所以JSP声明部分定义的变量和方法可以使用private、public等访问控制修饰符,也可以使用static修饰,将其变成类属性和类方法,但不能使用abstract修饰声明部分的方法,因为抽象方法将导致JSP对应Servlet变成抽象类,从而导致无法实例化。
打开多个浏览器页面,甚至可以在不同机器上打开浏览器来刷新该页面,将发现所有不同的客户端访问的count是连续的,即所有客户端共享同一个count变量。这是因为:JSP页面会编译生成一个Servlet类,每个Servlet在容器中只有一个实例;在JSP中声明的变量是成员变量,成员变量只在创建实例时初始化,该变量的值将一直保存,直到实例销毁。
值得注意的是,info()的值也可正常输出。因为JSP声明的方法其实是在JSP编译中生成的Servlet的实例方法——Java里的方法是不能独立存在的,即使在JSP页面中也不行。JSP声明中独立存在的方法,只是一种假象。
1.3,输出JSP表达式
<%=%>称作jsp表达式,用于将已经声明的变量或者表达式输出到网页上面。
<div> <%! public int count; public String info() { return "hello"; } %> <%=count++%> <%=info()%> </div>
输出表达式语法代替了原来的out.print输出语句,该页面的执行效果与前一个程序没有区别。输出表达式语法后不能有分号。
1.4,JSP脚本
<% %>叫做脚本片段,其中写的内容会翻译在Servlet的Service方法中,显然我们可以在Service方法中定义局部变量或者调用其他方法,但是不能在Service中再定义其他的方法,也就是我们可以在<%%>中定义局部变量或者调用方法,但不能定义方法。在jsp页面可以有多个脚本片段,但是多个脚本片段之间要保证结构完整。
<div> <table bgcolor="#9999dd" border="1" width="300px"> <% for (int i=0;i<10;i++){ %> <tr> <td>循环值:</td> <td><%=i%></td> </tr> <% } %> </table> </div>
打开编译后的代码:
try { response.setContentType("text/html;charset=UTF-8"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; out.write("\n"); out.write("\n"); out.write("<html>\n"); out.write("<head>\n"); out.write(" <title>Test</title>\n"); out.write("</head>\n"); out.write("<body>\n"); out.write("<div>\n"); out.write(" <table bgcolor=\"#9999dd\" border=\"1\" width=\"300px\">\n"); out.write(" "); for (int i=0;i<10;i++){ out.write("\n"); out.write(" <tr>\n"); out.write(" <td>循环值:</td>\n"); out.write(" <td>"); out.print(i); out.write("</td>\n"); out.write(" </tr>\n"); out.write(" "); } out.write("\n"); out.write(" </table>\n"); out.write("</div>\n"); out.write("</body>\n"); out.write("</html>\n"); } catch (java.lang.Throwable t) { if (!(t instanceof javax.servlet.jsp.SkipPageException)){ out = _jspx_out; if (out != null && out.getBufferSize() != 0) try { if (response.isCommitted()) { out.flush(); } else { out.clearBuffer(); } } catch (java.io.IOException e) {} if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); else throw new ServletException(t); } } finally { _jspxFactory.releasePageContext(_jspx_page_context); }
由上面代码片段可以看出,JSP脚本将转换成Servlet里_jspService方法的可执行代码。这意味着在JSP小脚本部分也可以声明变量,但在JSP脚本部分声明的变量是局部变量,但不能用private、public等访问控制符修饰,也不可使用static修饰。
实际上不仅JSP小脚本部分会转换成_jspService方法里的可执行代码,JSP页面里的所有静态内容都将由_jspService方法里输出语句来输出,这就是JSP脚本可以控制JSP页面中静态内容的原因。由于JSP脚本将转换成_jspService方法里的可执行性代码,而Java不允许在方法里定义方法,所以JSP脚本里不能定义方法。
<%@ page import="java.sql.*" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Test</title> </head> <body> <div> <table bgcolor="#9999dd" border="1" width="300px"> <% Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "123456"); String sql = "select * from student"; Statement statement = connection.createStatement(); ResultSet resultset = statement.executeQuery(sql); while (resultset.next()){ %> <tr> <td><%=resultset.getString(1)%></td> <td><%=resultset.getString(2)%></td> </tr> <% } %> </table> </div> </body> </html>
上面连接数据库需要用到数据库驱动架包,需要将驱动复制到tomcat的lib下面:E:\apache\apache-tomcat-8.5.46\lib
2,JSP的三个编译指令
JSP的编译指令是通过JSP引擎的消息,它不直接生成输出。编译指令都有默认值,因此开发人员无须为每个指令设置值。
- page:该指令是针对当前页面的指令
- include:用于指定包含另一个页面
- taglib:用于定义和访问自定义标签
编译指令的语法格式:<%@ 编译指令名 属性名="属性值" ...%>
2.1,page指令
page指令通常位于JSP页面的顶端,一个JSP页面可以使用多条page指令。
<%page [language="Java"] 声明当前JSP页面使用的脚本语言的种类,因为页面是JSP页面,该属性的值通常都是java,该属性的默认值也是java,所以通常无需设置。 [extends="package.class"] 指定JSP页面编译所产生的Java类所继承的父类,或所实现的接口。 [import="package.class"]
用来导入包。下面几个包是自动导入的,不需要,不需要显式导入。默认导入的包有:java.lang.*、javax.servlet.*、javax.servlet.jsp.*、javax.servlet.http.*。 [session="true|false"] 设定这个JSP页面是否需要HTTP Session。 [buffer="none|8KB|size KB"] 指定输出缓冲区大小。输出缓冲区的JSP内部对象:out用于缓存JSP页面对客户浏览器的输出,默认值为8KB,可以设置为none,也可以设置为其他的值,单位为KB。 [autoFlush="true|false"] 当输出缓冲区即将溢出时,是否需要强制输出缓冲区的内容。设置为true时为正常输出;如果设置为false,则会在buffer溢出时产生一个异常。 [isThreadSafe="true|false"] 设置线程是否安全。 [info="text"] 设置该JSP程序的信息,也可以看做其说明,可以通过Servlet.getServletInfo()方法获取该值。如果在JSP页面中,可直接调用getServletInfo()方法获取该值,因为JSP页面的实质就是Servlet。 [errorPage="relativeURL"] 指定错误处理页面。如果本页面产生了异常或错误,而该JSP页面没有对应的处理代码,则会自动调用该属性所指定的JSP页面。 [contentType="mimeType[;charset=characterSet]"|"text/html;charSet=ISO-8859-1"] 用于设定生成网页的文件格式和编码字符集,即MIME类型和页面字符集类型,默认的MIME类型是text/html;默认字符集时ISO-8859-1. [pageEncoding="ISO-8859-1"] 指定生成的网页的编码字符集 [isErrorPage="true|false"] 是否采用ErrorPage %> <%@ page import="java.sql.*" %> <%@ page contentType="text/html;charset=UTF-8" language="java" language="java" errorPage=""%>
2.2,include指令
使用include指令,可以将一个外部文件嵌入到当前JSP文件中,同时解析这个页面中的JSP语句(如果有的话)。这个静态的include语句,它会把目标页面的其他编译指令也包含进来。
include既可以包含静态的文本,也可以包含动态的JSP页面。静态的include编译指令会将被包含的页面加入页面,融合成一个页面,因此被包含页面甚至不需要是一个完整的页面。
include编译指令的语法如下:<%@include file="relativeURLSpec">
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Test</title> </head> <body> <div> <%@include file="detail.jsp"%> </div> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="java.sql.*" %> <table bgcolor="#9999dd" border="1" width="300px"> <% Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "123456"); String sql = "select * from student"; Statement statement = connection.createStatement(); ResultSet resultset = statement.executeQuery(sql); while (resultset.next()){ %> <tr> <td><%=resultset.getString(1)%></td> <td><%=resultset.getString(2)%></td> </tr> <% } %> </table>
2.3,taglib指令
taglib:用于定义和访问自定义标签
https://shao12138.blog.csdn.net/article/details/81837808
3,JSP的7个动作指令
动作指令与编译指令不同,编译指令是通知Servlet引擎的处理消息,而动作指令只是运行时的动作。编译指令在将JSP编译成Servlet时起作用;而处理指令通常可替换成JSP脚本,它只是JSP脚本的标准化。
- jsp:forward:执行页面转向,将请求的处理转发到下一个页面。
- jsp:param:用于传递参数,必须与其他支持参数的标签一起使用。
- jsp:include:用于动态引入一个JSP页面。
- jsp:plugin:用于下载JavaBean或Applet到客户端执行。
- jsp:useBean:创建一个JavaBean的实例。
- jsp:setProperty:设置JavaBean实例的属性值。
- jsp:getProperty:输出JavaBean实例的属性值。
3.1,forward指令
forward指令用于将页面响应转发到另外的页面。既可以转发到静态的HTML页面,也可以转发到动态的JSP页面,或者转发到容器中的Servlet。
JSP1.0:<jsp:forward page="{relativeURL|<%=expression%>}"> JSP2.0:转发时增加了额外的请求参数。增加的请求可以通过HttpServletRequest类的getParameter()方法获取。 <jsp:forward page="{relativeURL|<%=expression%>}"> {<jsp:param.../>} </jsp>
<jsp:forward page="detail.jsp"> <jsp:param name="age" value="23"/> </jsp:forward>
<%=request.getParameter("age")%>
在地址栏,用户的请求并没有发生变化,但页面内容全变被forward目标页的内容。另外通过第二页的数据可以看出forward指令不会丢失请求参数。
从表面上看,<jsp:forward>指令给人一种感觉:它是将用户请求“转发”到了另一个新页面,但实际上<jsp:forward>并没有重新向新页面发送请求,它只是完全采用了新页面来对用户生成响应——请求仍然是一次请求,所以请求参数、请求属性都不会丢失。
3.2,include指令
include指令是一个动态include指令,也用于包含某个页面,它不会导入被include页面的编译指令,仅仅将被导入页面的body内容插入本页面。
JSP1.0:<jsp:include page="{relativeURL|<%=expression%>}" flush="true"> JSP2.0:转发时增加了额外的请求参数。增加的请求可以通过HttpServletRequest类的getParameter()方法获取。 <jsp:include page="{relativeURL|<%=expression%>}" flush="true"> {<jsp:param.../>} </jsp>
实际上,forward动作指令和inlude动作指令十分相似(语法基本一样),它们都采用方法来引入目标页面,通过查看JSP页面所生成的Servlet代码可以看出:forward指令使用_jspx_page_context的forward()方法来引入目标页面,而inlude指令则使用通过JspRuntimeLibrary的include()方法来引入目标页面。
区别在于:执行forward时,被forward的页面将完全代替原有页面;而执行inlude时,被include的页面只是插入原有页面。简而言之,forward拿目标页面代替原有页面,而include则拿目标页面插入原有页面。
静态导入和动态导入:
对于静态包含,<%@include%>,中包含的文件(无论html文件还是jsp文件),只是简单的嵌入到主文件中,就是在jsp页面转化成Servlet时才嵌入到主文件中,因为运行的结果是只生成了一个Servlet。
而对于动态包含< jsp:incude>,如果被包含文件是动态的(jsp文件),那么就会生成两个Servlet,也就是被包含文件也要经过jsp引擎编译执行生成一个Servlet,两个Servlet通过request和reponse进行通信(包含的jsp是一个完整的文件有html、body等标签)。如果被包含的文件是静态的(html文件),那么这种情况和<%@include>就很相似,只生成了一个Servlet,但是他们之间没有进行简单的嵌入,而依然是通过request和reponse进行的通信。
- 静态导入是将被导入页面的代码完全融入,两个页面融合成一个整体Servlet;而动态导入则在Servlet中使用include方法来引入被导入页面的内存。
- 动态导入可以包含额外的参数。
3.3,useBean、setProperty、getProperty指令
这三个指令都是与JavaBean相关的指令,其中
- useBean指令用于在JSP页面中初始化一个Java实例。
- setProperty指令用于为JavaBean实例的属性设置值。
- getProperty指令用于输出JavaBean实例的属性。
如果多个JSP页面中需要重复使用某段代码,则可以把这段代码定义成Java类方法,然后让多个JSP页面调用该方法即可,这样可以达到较好的代码复用。
<jsp:useBean id="name" class="classname" scope="page|request|session|application"/> id:JavaBean的属性名 class:JavaBean的实现类 scope:用于指定JavaBean实例的作用范围 page:仅在该页面有效 request:本次请求有效 session:本次会话有效 application:本应用内一直有效
<jsp:setProperty name="BeanName" property="propertyName" value="value"/> name:确定需要设定的JavaBean的实例名 property:确定需要设置的属性名 value:确定需要设置的属性值
<jsp:getProperty name="BeanName" property="propertyName"/> name:确定需要设定输出的JavaBean的实例名 property:确定需要输出的属性名
<jsp:useBean id="p1" class="Pojo.Person" scope="page"> <jsp:setProperty name="p1" property="name" value="燕双嘤"/> <jsp:setProperty name="p1" property="age" value="23"/> </jsp:useBean> <jsp:getProperty name="p1" property="name"/> <jsp:getProperty name="p1" property="age"/> ===================================================== public class Person { private String name; private String age; public Person() { } public Person(String name, String age) { this.name = name; this.age = age; } //省略set,get }
默认构造方法必须有,自定义构造方法可有可无,建议都加上。
3.4,plugin指令
plugin指令主要用于下载服务器端的JavaBean或Applet到客户端执行。由于程序在客户端执行,因此客户端必须安装虚拟机。
实际上由于现在很少使用Applet,而且就算要使用Applet,也完全可以使用支持Applet的HTML标签,所以jsp:plugin标签的使用场景很少。
3.5,param指令
param指令用于设置参数值,这个指令本身不能单独使用,因为单独使用param指令没有任何意义。param指令可以与以下三个指令结合使用。
- jsp:include:当与include指令结合使用时,param指令用于将参数值传入被导入的页面;
- jsp:forward:当与forward指令结合使用时,param指令用于将参数值传入被转向的页面;
- jsp:plugin:当与plugin指令结合使用时,则用于将参数传入页面中的JavaBean实例或Applet实例。
param指令语法:<jsp:param name="paramName" value="paramValue"/>