JSP本质上就是一个HTML内容和Java代码的混合,学习JSP就是学习如何在HTML中嵌入Java可编程代码。
JSP的标志符号就是:<% %>。其中如果:(以上写法注意%后空格和末尾的分号)
<%! String name = "大飞哥"; %>
<h1>源栈欢迎你 <%= name %> </h1>或者表达式运算结果的输出
<h1>源栈欢迎你, <%= name+"(飞哥)" %></h1>
<% name += ",皮"; %>代码块中的代码,可以一行,也可以多行。你在Java中怎么写的,这里就可以怎么写(变量赋值,分支循环……)
<% String name = "fg"; name+="(飞哥)"; if(LocalDate.now().isAfter(LocalDate.of(2021, 11, 19))){} %>在这种代码块中,有一种特殊的方法,执行后会输出字符串到HTML页面中:
<% out.print(name); %>
以上是存文本输出,如果要有HTML标签的话(不建议):
out.print("<p>" + name + "</p>");
注意:前面没有System.前缀,因为这不是控制台输出!而是JspWriter
代码块里面的注释,和普通Java代码一样
<% String name = "fg"; /*name+="(飞哥)";*/ out.print(name); //System.out %>
代码块外面的注释,使用:<%-- --%>
<%-- <%!String name = "大飞哥";%> --%> <%-- <%= name %> --%>
注意和HTML注释的区别:
<!-- 源栈欢迎你 -->
在JSP的代码块中,不能出现HTML标签。所以这样的写法是无法编译通过的:
<% boolean smart = true; %> <% if(smart){ <h1>飞哥帅呆了</h1> } %>要么我们使用out.print():
out.print("<h1>飞哥帅呆了</h1>");
要么我们就需要将非HTML内容用<%%>分别包裹起来:
<% if(smart) {%> <h1>飞哥帅呆了</h1> <%} %>
else也一样:
<% if(smart) {%> <h1>飞哥帅呆了</h1> <%} else { %> <h1>飞哥自恋狂</h1> <%} %>
一样可以分支嵌套,switch也以此类推,略。
for循环:
<% for(int i = 0; i< 5; i++) { %> <p><%=i%></p> <% } %>
while循环:
<%! int i = 0; %> <% while(i<5){ %> <p><%=i%></p> <% i++; %> <% } %>
演示举例说明:一起帮哪些页面
一个JSP页面可以包含多个指令,指令以<%@ %>标记。常用的有:
@后接page,再后面接键值对:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.time.DayOfWeek"%>
page指令可以自由拆分/合并(演示,略)
引入其他页面(.jsp或.html)
在@后接include,然后由file指定页面路径:页面可以是jsp,也可以是html;路径可以是相对的,也可以是绝对的。
<%@ include file="shared/_navigator.jsp" %>
<%@ include file="/_footer.html" %>
使用include指令就可以让我们把多个页面共用的部分(比如页头/页脚)抽出来,供其他页面反复重用,告别静态页面大量的Ctrl+C和Ctrl+V。
<!-- URL包含了:协议、域名和端口 --> request.getRequestURL(): <%= request.getRequestURL() %> <br /> <!-- URI仅有端口之后的path部分 --> request.getRequestURI(): <%= request.getRequestURI() %> <br /> <!-- ServletPath去掉了Servlet名 --> request.getServletPath():<%= request.getServletPath() %><br /> <!-- 获取协议、域名和端口 --> request.getServerName():<%= request.getServerName() %><br /> request.getProtocol():<%= request.getProtocol() %><br /> request.getServerPort():<%= request.getServerPort() %><br />
GET请求的url参数(query string),或者POST请求的form data
<%= request.getQueryString() %> <br /> <%= request.getParameter("n") %><br />请求的method(GET还是POST等):
<%= request.getMethod() %> <br />
以及客户端的一些信息:
<!-- 客户端信息,相对于服务器就是remote --> request.getRemoteAddr():<%= request.getRemoteAddr() %> request.getRemotePort():<%= request.getRemotePort() %>其他所有的信息都还可以通过header获取:比如referer(上一页)
<%= request.getHeader("referer")%> <br />
演示:在另一个页面:
<a href="Welcome.jsp">welcome</a>
最后,来个大杀技!
<% Enumeration<String> names = request.getHeaderNames(); while(names.hasMoreElements()){ String name = names.nextElement(); out.println( name + " : " + request.getHeader(name) + "<br />"); } %>
可以看出,cookie是可以从request中获取的(由response生成)
此外,还有response、session、pageContext、application、exception等内置对象,完全可以满足web开发所需……
实际开发中经常会出现页面自动跳转的场景,比如:未登录用户访问一个需要登录才能访问的页面,17bang会自动转到登录页面。
JSP中有两种方式可以实现这种需求:
<jsp:forward page="/logon.jsp"></jsp:forward>
<% response.sendRedirect("logon.jsp"); %>
#常见面试题# forward和redirect的区别:(复习:状态码301和302)
|
forward |
redirect |
需要客户端参与 |
否 |
是 |
客户端发起请求次数 |
1 |
2 |
浏览器地址栏显示 |
最初请求的地址 |
跳转过后的地址 |
注意:foward和sendRedirect()使用的路径格式不一样:
<%= request.getContextPath() %>
ContextPath用于确定servlet(后文详述)。
所以我们这里使用相对路径,一定要使用绝对路径的话,需要拼接context path:
<% response.sendRedirect(request.getContextPath() + "/logon.jsp"); %>
我们可以把大量的复杂逻辑放到JavaBean中,这样页面代码就可以变得更加的简洁清爽(复习:PageModel模式)。这是JSP一样能开发大型项目的底气!
使用JSP动作useBean引入,class指定类名,id为当前页使用的“别名”(或者该类的变量名),在当前页使用:
<jsp:useBean id="author" class="bean.jsp.bang.User"></jsp:useBean>可以用JSP动作读/写Bean的属性
<jsp:setProperty property="name" name="author" value="飞哥"/> <jsp:getProperty property="name" name="author"/>还可以直接url参数获值赋予给JavaBean的属性,比如:/Welcome.jsp?n=fg
<jsp:setProperty property="name" name="author" param="n"/>
如果不断的完善规范Bean,就会形成PageModel的框架
public void init() { this.name = "飞哥"; //取自数据库 }
<% author.init(); %>
public void save() { //模拟保存到数据库 System.out.println(this.name + "has been saved"); }
<jsp:setProperty property="name" name="author" param="n"/> <% author.save(); %>
对外tomcat作为服务器响应所有HTTP请求,但是对内tomcat本身只是一个容器,它的功能实现依赖于其内部的servlet。
servlet是继承自javax.servlet.http.HttpServlet的类,比如tomcat就默认带有两个servlet:
public class org.apache.catalina.servlets.DefaultServlet extends javax.servlet.http.HttpServlet {
public class org.apache.jasper.servlet.JspServlet extends javax.servlet.http.HttpServlet
tomcat中有哪些servlet,servlet间如何分工,都是由web.xml配置的。
tomcat自带一个默认的web.xml:(我们也可以在项目中添加自定义的web.xml,自定义的web.xml拥有更高的优先级,SpringMVC中使用)
其中就可以看到已经配置了
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>不需要特殊处理的所有基本的HTTP请求,如html页面、图像、.js/.css文件等静态资源
<servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> </servlet-mapping>
即:所有.jsp结尾的文件请求由jsp servlet负责
servlet会将JSP页面解析成一个java类
演示:在eclipse中双击server查看tomcat的工作路径
-Dcatalina.base="D:\Users\86186\eclipse-workspace-2021-09\.metadata\.plugins\org.eclipse.wst.server.core\tmp1"
说明:eclipse中的tomcat是被当做插件使用的,上述目录被用于存放tomcat工作时所需文件资料。
其下\work\Catalina\localhost\jsp.17bang\org\apache\jsp中存放着.jsp对应的java类(源文件+编译后文件)
所有类都继承自HttpJspBase:public final class Welcome_jsp extends org.apache.jasper.runtime.HttpJspBase其中最核心的方法就是:
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)里面大量的调用out.write()方法用于向客户端输出内容:
out.write("<!DOCTYPE html>\r\n"); out.write("<html>\r\n"); out.write("<head>\r\n"); out.write("<meta charset=\"UTF-8\">\r\n");
演示:观察本章节JSP内容(变量赋值/分支循环/指令动作等)如何生成相应的Java代码。
理解:
#常见面试题:<%@include> 和 <jsp:include>的区别?#
这个问题看生成的HttpJspBase代码最直观:
out.write("<p>导航栏</p>\r\n"); out.write("<a href=\"../Welcome.jsp\">welcome</a>");
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "shared/_navigator.jsp", out, false);
区别 |
@include |
<jsp:include |
执行时间 |
翻译阶段 |
在请求处理阶段 |
引入的内容 |
所生成的应答文本 |
一个include()方法 |
当变成Web项目之后,因为整个项目运行在tomcat这个容器中,就不能再像控制台一样直接JDBC了。
这时候我们需要在tomcat中注册
首先在context.xml中添加:
<Resource name="jndi/mysql17bang" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/17bang" username="root" password="" maxActive="20" maxIdle="10" maxWait="10000" />然后在web.xml引入:
<resource-ref> <description>JNDI DataSource</description> <res-ref-name>jndi/mysql17bang</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>最后Java代码中:
Context ctx = new InitialContext(); //注意这个前缀:java:comp/env/ DataSource ds = (DataSource) ctx.lookup("java:comp/env/jndi/mysql17bang"); Connection conn = ds.getConnection(); System.out.println(conn.isClosed());注意选择正确的import:
import javax.naming.*;
多快好省!前端后端,线上线下,名师精讲
更多了解 加: