JSP入门基础知识详细版(通俗易懂)
JSP 第一篇:
概述、原理、周期、指令、行为、内置对象、JavaBean
(一) JSP概述以及简单使用
什么是JSP?
JSP全名为Java Server Pages,java服务器页面。JSP是一种基于文本的程序,其特点就是HTML
和Java代码共同存在!
为什么需要JSP?
JSP是为了简化Servlet的工作出现的替代品,Servlet输出HTML非常困难,JSP就是替代Servlet输出HTML的
JSP还有必要学吗?
在MVC中,JSP属于展示层,但是JSP却又可以写一定的业务,甚至跑去做数据层的事情,这样开发中就会变得无比混乱,也增加了开发的困难程度,所以将展示层与业务层分开就成为了主流,也就是我们说的前后端分离,但是事无绝对,确实一些比较老的项目仍然在跑jsp,不管你会不会写,你总得碰到能看懂吧,如果已经接近找工作,确实还是以比较流行的技术学习比较好,但是若作为学生,时间还是比较富裕的,很多本科也必然都会讲,学习一下也是挺好的,况且JSP与Servlet也是息息相关的,我认为,学它就是为了知道为什么以后会用别的技术代替它(狗头保命),废话有点多了,还是有一点需要的朋友可以简单看一看,希望给你能有一点帮助
(二) JSP的工作原理
Tomcat访问任何的资源都是在访问Servlet!,当然了,JSP也不例外!JSP本身就是一种Servlet。为什么说JSP本身就是一种Servlet呢?
其实JSP在第一次被访问的时候会被编译为HttpJspPage类(该类是HttpServlet的一个子类)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>简单使用JSP</title>
</head>
<body>
<%
String s = "HelloWorld";
out.println(s);
%>
编译过程是这样子的:
浏览器第一次请求1.jsp时,Tomcat会将1.jsp转化成1_jsp.java这么一个类,并将该文件编译成class文件。编译完毕后再运行class文件来响应浏览器的请求。
以后访问1.jsp就不再重新编译jsp文件了,直接调用class文件来响应浏览器。当然了,如果Tomcat检测到JSP页面改动了的话,会重新编译的。
既然JSP是一个Servlet,那JSP页面中的HTML排版标签是怎么样被发送到浏览器的?我们来看下上面1_jsp.java的源码就知道了。原来就是用write()出去的罢了。说到底,JSP就是封装了Servlet的java程序罢了
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<title>简单使用JSP</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n")
有人可能也会问:JSP页面的代码服务器是怎么执行的?再看回1_jsp.java文件,java代码就直接在类中的service()中
String s = "HelloWorld";
out.println(s);
(三) 声明周期
JSP也是Servlet,运行时只有一个实例,JSP初始化和销毁时也会调用Servlet的init()和destroy()方法。另外,JSP还有自己初始化和销毁的方法
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
public void _jspDestroy() {
}
(四) 指令
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
作用:用于配置JSP页面,导入资源文件
格式: <%@ 指令名称 属性名1=属性值1 属性名2=属性值2 ... %>
-
contentType:相当于response.setContentType()
-
设置响应体的mime类型以及字符集
-
设置当前jsp页面的编码(只能是高级的IDE才能生效,如果使用低级工具,则需要设置pageEncoding属性设置当前页面的字符集)
pageEncoding="characterSet | ISO-8859-1"
-
-
import:导包
import="{package.class | package.*}, ..."
-
errorPage:当前页面发生异常后,会自动跳转到指定的错误页面
//主页面 <%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %> //错误后转到的页面 <%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %> 我们发现地址栏是没有变化的,所以属于是服务器跳转。以上的做法是单个页面设置的,如果我会有很多错误(JSP多的情况下,错误就会多),单个设置太麻烦了! 我们可以在web.xml文件中全局设置错误页,只要发生了404错误或者空指针异常的错误都会跳转到error.jsp页面上 <error-page> <error-code>404</error-code> <location>/error.jsp</location> </error-page> <error-page> <exception-type>java.lang.NullPointerException</exception-type> <location>/error.jsp</location> </error-page>
-
isErrorPage:标识当前也是是否是错误页面
- true:是,可以使用内置对象exception
- false:否。默认值。不可以使用内置对象exception
(五) 行为
JSP行为(JSP Actions)是一组JSP内置的标签,只书写少量的标记代码就能够使用JSP提供丰富的功能,JSP行为是对常用的JSP功能的抽象和封装。
JSP内置的标签称之为JSP行为,是为了能够和JSTL标签区分开来。(叫做JSP标签也行)
(1) include 行为
上面已经提及到了,include指令是静态包含,include行为是动态包含。其实include行为就是封装了request.getRequestDispatcher(String url).include(request,response)
include行为语法是这样的:
<jsp:include page=""/>
静态包含:<%@ include file="被包含页面"%>
动态包含:<jsp:include page="被包含页面" flush="true">
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>包含页头和页尾进来</title>
</head>
<body>
<jsp:include page="head.jsp"/>
<jsp:include page="foot.jsp"/>
</body>
jsp行为包含文件就是先编译被包含的页面,再将页面的结果写入到包含的页面中(1.jsp)
当然了,现在有静态包含和动态包含,使用哪一个更好呢?答案是:动态包含。
动态包含可以向被包含的页面传递参数(用处不大),并且是分别处理包含页面的(将被包含页面编译后得出的结果再写进包含页面)
【如果有相同名称的参数,使用静态包含就会报错!】!
(2) Param 行为
当使用<jsp:include>和<jsp:forward>
行为引入或将请求转发给其它资源时,可以使用<jsp:param>
行为向这个资源传递参数
(3) forward 行为
在Servlet中我们使用request.getRequestDispatcher(String url).forward(request,response)进行跳转。其实forward行为就是对其封装!
我们来看一下forward的语法
<jsp:forward page=""/>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>访问1.jsp就跳转到head.jsp</title>
</head>
<body>
<jsp:forward page="head.jsp"/>
</body>
</html>
如果我要传递参数,就要在forward行为嵌套param行为
在跳转到head.jsp时传入参数username值为aaa
<jsp:forward page="head.jsp">
<jsp:param name="username" value="aaa"/>
</jsp:forward>
<%
String ss = request.getParameter("username");
%>
获取到的参数是:
<%=ss%>
(4) directive 行为
directive的中文意思就是指令。该行为就是替代指令<%@%>
的语法的
· <jsp:directive.include file=""/> 相当于<%@include file="" %>
· jsp:directive.page/ 相当于<%@page %>
· jsp:directive.taglib/ 相当于<%@taglib %>
使用该指令可以让JSP页面更加美观!
使用scriptlet行为<jsp:scriptlet>
替代<%%>是同样一个道理
(5) javaBean 行为
JSP还提供了操作javaBean对象的行为,暂时记住JSP提供了javaBean行为来操作简单类即可!后面详细解释:
<jsp:useBean id=""/>
<jsp:setProperty name="" property=""/>
<jsp:getProperty name="" property=""/>
(六) JSP内置对象(直接使用)
JSP引擎在调用JSP对应的jspServlet时,会传递或创建9个与web开发相关的对象供jspServlet使用。JSP技术的设计者为便于开发人员在编写JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用
变量名 | 真实类型 | 作用 |
---|---|---|
pageContext | PageContext | 当前页面共享数据,还可以获取其他八个内置对象 |
request | HttpServletRequest | 一次请求访问的多个资源(转发) |
session | HttpSession | 一次会话的多个请求间 |
application | ServletContext | 所有用户间共享数据 |
response | HttpServletResponse | 响应对象 |
page | Object | 当前页面(Servlet)的对象 this |
out | JspWriter | 输出对象,数据输出到页面上 |
config | ServletConfig | Servlet的配置对象 |
exception | Throwable | 内置对象exception是java.lang.Exception类的对象 |
(七) 四种属性范围
到目前为止,我们已经学了4种属性范围了。
page【只在一个页面中保存属性,跳转页面无效】
requet【只在一次请求中保存属性,服务器跳转有效,浏览器跳转无效】
session【在一个会话范围中保存属性,无论何种跳转均有效,关闭浏览器后无效】
application【在整个服务器中保存,所有用户都可以使用】
4个内置对象都支持以下的方法:
- setAttribute(String name, Object o )
- getAttribute(String name)
- removeAttribute(String name)
※ 应用场景
- request:如果客户向服务器发请求,产生的数据,用户看完就没用了,像这样的数据就存在request域,像新闻数据,属于用户看完就没用的
- session:如果客户向服务器发请求,产生的数据,用户用完了等一会儿还有用,像这样的数据就存在session域中,像购物数据,用户需要看到自己购物信息,并且等一会儿,还要用这个购物数据结帐
- servletContext:如果客户向服务器发请求,产生的数据,用户用完了,还要给其它用户用,像这样的数据就存在servletContext域中,像聊天数据
(八) JavaBean
avaBean就是一个普通的java类,也称之为简单java对象--POJO(Plain Ordinary Java Object),是Java程序设计中一种设计模式,是一种基于 Java 平台的软件组件思想
JavaBean遵循着特定的写法,通常有以下的规则:
有无参的构造函数
成员属性私有化
封装的属性如果需要被外所操作,必须编写public类型的setter、getter方法
上面的文字看起来好像很高大上,javaBean其实非常简单,常见的学生类,书籍类就是按照特定写法、规则编写的一个JavaBean对象
为什么需要使用Javabean
使用javaBean的好处:封装,重用,可读!
JaveBean你可以理解为一辆货车,在你的java端和web页面进行数据传递的载体,你当然可以每个变量单独传递,或者使用集合传递,但是javabean可以使你的数据更有可读性,方便开发时明确变量的意义,也使其他阅读你代码的人能直接你的意图
如果bean类与数据库联合使用,一张表使用bean类,可以使你的代码更加简洁高效,易于理解,现在大多数框架都会使用这种机制。
JSP行为--JavaBean
JSP技术提供了三个关于JavaBean组件的动作元素,即JSP行为(标签),它们分别为:
jsp:useBean【在JSP页面中查找javaBean对象或者实例化javaBean对象】
jsp:setProperty【设置javaBean的属性】
jsp:getProperty【获取javaBean的属性】
※ JSP:useBean
<jsp:useBean>
标签用于在指定的域范围内查找指定名称的JavaBean对象:
存在则直接返回该JavaBean对象的引用。
不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
语法:
jsp:useBean id="实例化对象的名称" class="类的全名" scope="保存范围"/>
果JSP不支持<jsp:useBean>
这个行为,我们要使用Person类是这样使用的
<%--这里需要导入Person类--%>
<%@ page import="domain.Person" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body>
<%
//new出对象
Person person = new Person();
person.setName("admin");
System.out.println(person.getName());
%>
</body>
但是我们使用<jsp:useBean>
就非常整洁,不用导包,不用new对象
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body>
<jsp:useBean id="person" class="domain.Person" scope="page"/>
<%
person.setName("zhongfucheng");
System.out.println(person.getName());
%>
</body>
</html>
JavaBean中无参的构造函数改成有参的,会出现异常,这是因为<jsp:useBean>
的内部原理是 new了一个无参的构造函数
※ JSP:setProperty
<jsp:setProerty name="对象名称" property="属性名" param="参数名" value="值">
四种模式
<jsp:setProperty name="对象名称" property="*"/>自动匹配
<jsp:setProperty name="对象名称" property="属性名称"/>指定属性
<jsp:setProperty name="对象名称" property="属性名称" param="参数名称"/>指定参 数【很少用】
<jsp:setProperty name="对象名称" property="属性名称" value="内容"/>指定内容【很 少用】
当我们没有学习到<jsp:setProperty>
时,我们获取表单的信息,然后导入到javaBean对象中是这样的一种情况:
<jsp:useBean id="person" class="domain.Person" scope="page"/>
<%
int age = Integer.parseInt(request.getParameter("age"));
person.setAge(age);
System.out.println(person.getAge());
%>
而我们使用<jsp:setProperty>
后,代码更少,功能更强大
<jsp:useBean id="person" class="domain.Person" scope="page"/>
<%--指定属性名称为age--%>
<jsp:setProperty name="person" property="age"/>
<%
System.out.println(person.getAge());
%>
代码少很直观的可以看出来,但是强大在什么地方呢?
表单提交过来的数据都是字符串,在我们没有用<jsp:setProperty>
前,我们存储设置int类型或其他非字符串类型的数据是需要强转的!但是<jsp:setProperty>
不需要我们强转,它内部自动帮我们转换了!
下面再通过自动匹配来感受它的强大
<jsp:useBean id="person" class="domain.Person" scope="page"/>
<%--property的值设置为*就代表自动匹配--%>
<jsp:setProperty name="person" property="*"/>
<%
System.out.println(person.getAge());
System.out.println(person.getName());
%>
为什么Property的值可以将表单传递过来的数据封装到JavaBean对象中?
JavaBean属性名要和表单的name的名称一致
是通过反射来做的,调用了内省的方法!
※ JSP:getProperty
<jsp:getProperty name="对象名" property="属性名"/>
<%--使用<jsp:getProperty>输出--%>
<jsp:getProperty name="person" property="username"/>
<jsp:getProperty name="person" property="age"/>
JSP 第二篇:
EL运算符:概述、内置对象、数据回显、自定义函数、EL函数库
(一) 概述
EL:Expression Language 表达式语言
它的作用就是替换和简化jsp页面中java代码的编写
EL表达式支持简单的运算符:加减乘除取摸,逻辑运算符。empty运算符(判断是否为null),三目运算符
empty运算符可以判断对象是否为null,用作于流程控制!
三目运算符简化了if和else语句,简化代码书写
<%
List<Person> list = null;
%>
${list==null?"list集合为空":"list集合不为空"}
(二) 内置对象
EL表达式主要是来对内容的显示,为了显示的方便,EL表达式提供了11个内置对象
pageContext 对应于JSP页面中的pageContext对象(注意:取的是pageContext对象)
pageScope 代表page域中用于保存属性的Map对象
requestScope 代表request域中用于保存属性的Map对象
sessionScope 代表session域中用于保存属性的Map对象
applicationScope 代表application域中用于保存属性的Map对象
param 表示一个保存了所有请求参数的Map对象
paramValues 表示一个保存了所有请求参数的Map对象,它对于某个请求参数,返回的是一个string[]
header 表示一个保存了所有http请求头字段的Map对象
headerValues 同上,返回string[]数组。
cookie 表示一个保存了所有cookie的Map对象
initParam 表示一个保存了所有web应用初始化参数的map对象
(三) 数据回显
<%--模拟数据回显场景--%>
<%
User user = new User();
user.setGender("male");
//数据回显
request.setAttribute("user",user);
%>
<input type="radio" name="gender" value="male" ${user.gender=='male'?'checked':'' }>男
<input type="radio" name="gender" value="female" ${user.gender=='female'?'checked':'' }>女
(四) 自定义函数
EL自定义函数用于扩展EL表达式的功能,可以让EL表达式完成普通Java程序代码所能完成的功能
开发HTML转义的EL函数
我们有时候想在JSP页面中输出JSP代码,但是JSP引擎会自动把HTML代码解析, 输出给浏览器。此时我们就要对HTML代码转义。
步骤:
编写一个包含静态方法的类(EL表达式只能调用静态方法),该方法很常用,Tomcat都有此方法,可在webappsexamplesWEB-INFclassesutil中找到
public static String filter(String message) {
if (message == null)
return (null);
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuilder result = new StringBuilder(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
在WEB/INF下创建tld(taglib description)文件,在tld文件中描述自定义函数
<?xml version="1.0" encoding="ISO-8859-1"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<tlib-version>1.0</tlib-version>
<short-name>myshortname</short-name>
<uri>/zhongfucheng</uri>
<!--函数的描述-->
<function>
<!--函数的名字-->
<name>filter</name>
<!--函数位置-->
<function-class>utils.HTMLFilter</function-class>
<!--函数的方法声明-->
<function-signature>java.lang.String filter(java.lang.String)</function-signature>
</function>
</taglib>
在JSP页面中导入和使用自定义函数,EL自定义的函数一般前缀为"fn",uri是"/WEB-INF/tld文件名称"
<%@ page language="java" contentType="text/html" pageEncoding="UTF-8" %>
<%@taglib prefix="fn" uri="/WEB-INF/ideal.tld" %>
<html>
<head>
<title></title>
</head>
<body>
//完成了HTML转义的功能
${fn:filter("<a href='#'>点这里</a>")}
</body>
</html>
(五) EL函数库(fn方法库)
- 由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用。
- 其实EL函数库就是fn方法库,是JSTL标签库中的一个库,也有人称之为fn标签库,但是该库长得不像是标签,所以称之为fn方法库
- 既然作为JSTL标签库中的一个库,要使用fn方法库就需要导入JSTL标签!要想使用JSTL标签库就要导入jstl.jar和standard.jar包!
- 所以,要对fn方法库做测试,首先导入开发包(jstl.jar、standard.jar)
在JSP页面中指明使用标签库
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
JSP 第三篇:
JSTLd的简单认识、三个常用对象
JSTL全称为 JSP Standard Tag Library 即JSP标准标签库
JSTL作为最基本的标签库,提供了一系列的JSP标签,实现了基本的功能:集合的遍历、数据的输出、字符串的处理、数据的格式化等等!
为什么使用
EL表达式可以很方便地引用一些JavaBean以及其属性但是仍然不够完美,它不能遍历集合,做逻辑的控制。
Scriptlet的可读性,维护性,重用性都十分差!JSTL与HTML代码十分类似,遵循着XML标签语法,使用JSTL让JSP页面显得整洁,可读性非常好,重用性非常高,可以完成复杂的功能!
在JSP中不推荐使用scriptlet输出,推荐使用JSP标签
使用JSTL标签库步骤
- 导入jstl相关jar包
- 引入标签库:taglib指令:
<%@ taglib %>
- 使用标签
Core标签库
core标签库是JSTL的核心标签库,实现了最基本的功能:流程控制、迭代输出等操作!
core标签库的前缀一般是c
常用的三个JSTL标签
(一) c:if
属性:
test 必须属性,接受boolean表达式
如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容
- 注意:c:if 标签没有else情况,想要else情况,则可以在定义一个c:if标签
<%--如果带过来的名字是admin,那么可以登陆--%>
<c:if test="${param.name=='admin'}">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登陆">
</c:if>
<%--如果带过来的名字是admin888,那么就是注册--%>
<c:if test="${param.name=='admin888'}">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="注册">
</c:if>
(二) c:choose
它相当于java代码的switch语句
使用choose标签声明,相当于switch声明
使用when标签做判断,相当于case
使用otherwise标签做其他情况的声明,相当于default
<c:choose>
<c:when test="${param.name=='admin'}">
欢迎管理员
</c:when>
<c:when test="${param.name=='user'}">
欢迎用户
</c:when>
<c:otherwise>
识别不出你是谁
</c:otherwise>
</c:choose>
(三) c:forEach
forEach为循环标签,相当于Java中的while和for
之前我们在使用EL表达式获取到集合的数据,遍历集合都是用scriptlet代码循环,现在我们学了forEach标签就可以舍弃scriptlet代码
向Session中设置属性,属性的类型是List集合
向Session中设置属性,属性的类型是List集合
遍历session属性中的List集合,items:即将要迭代的集合。var:当前迭代到的元素
<%
List list = new ArrayList<>();
list.add("admin");
list.add("zhangsan");
list.add("lisi");
session.setAttribute("list", list);
%>
=====================================================
<c:forEach var="list" items="${list}" >
${list}<br>
</c:forEach>
Map对象有稍微地不一样保存的不是每个迭代的对象,而是Map.Entry
<%
Map map = new HashMap();
map.put("1", "tom");
map.put("2", "jack");
map.put("3", "jack”);
session.setAttribute("map",map);
%>
<c:forEach var="me" items="${map}" >
${me.key} ${me.value}<br>
</c:forEach>
特别说明:本篇中 第二 第三篇部分内容转载来自 java3y 所写jsp第四篇内容,在作者基础上摘出片段,附上链接:
https://juejin.im/post/5a7919045188257a76630a23
结尾:
如果内容中有什么不足,或者错误的地方,欢迎大家给我留言提出意见, 蟹蟹大家 !_
如果能帮到你的话,那就来关注我吧!(系列文章均会在公众号第一时间更新)
在这里的我们素不相识,却都在为了自己的梦而努力 ❤
一个坚持推送原创Java技术的公众号:理想二旬不止