1

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)
※ 应用场景
  1. request:如果客户向服务器发请求,产生的数据,用户看完就没用了,像这样的数据就存在request域,像新闻数据,属于用户看完就没用的
  2. session:如果客户向服务器发请求,产生的数据,用户用完了等一会儿还有用,像这样的数据就存在session域中,像购物数据,用户需要看到自己购物信息,并且等一会儿,还要用这个购物数据结帐
  3. 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("&lt;");
                break;
            case '>':
                result.append("&gt;");
                break;
            case '&':
                result.append("&amp;");
                break;
            case '"':
                result.append("&quot;");
                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/5a7919...

结尾:

如果内容中有什么不足,或者错误的地方,欢迎大家给我留言提出意见, 蟹蟹大家 !^_^

如果能帮到你的话,那就来关注我吧!(系列文章均会在公众号第一时间更新)

在这里的我们素不相识,却都在为了自己的梦而努力 ❤

一个坚持推送原创Java技术的公众号:理想二旬不止


二境志
191 声望26 粉丝

引用和评论

0 条评论