JSP简单介绍

Posted 鬼王呵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JSP简单介绍相关的知识,希望对你有一定的参考价值。

JSP

  • JSP–Java Server Pages,和servlet技术一样,都是SUN公司定义的一种用于开发动态的web资源的技术。
  • JSP技术最大的特点在于:写JSP就像在写html,但它相比html而言,html只能为用户提供静态数据,而JSP技术允许在页面中嵌套java代码,为用户提供动态的数据。

JSP原理

  • 浏览器访问JSP页面时,Web服务器时如何调用并执行一个JSP页面的?
  • Web服务器在执行JSP页面时,是如何把JSP页面中的html排版标签是如何执行的?
  • JSP页面中的java代码服务器是如何执行的?
  • Web服务器在调用JSP时,会给JSP提供一些什么java对象?

JSP实际上就是Servlet,它是由容器翻译成Servlet源文件,再编译,用户看到的是Servlet的响应结果。

JSP最佳实践

Servlet作为Web应用中的控制器组件,JSP技术作为数据显示模板。

JSP语法

  • JSP模板:JSP页面中HTML都是模板代码。
  • JSP表达式:
    • 作用:将程序数据输出到客户端
    • 语法:<%= 变量或表达式%> 注:其中没有分号。
  • JSP脚本片段

    • 作用:在JSP中编写java代码
    • 语法:
    <% 
    第一行java代码;
    第二行java代码;
    ...
    %>
  • JSP声明:JSP页面中编写的所有代码,默认是翻译到Servlet的_jspService方法中,而JSP声明中的java代码被翻译到_jspService方法的外面。

    • 语法:
    <%!
    java代码;...
    %>
    • JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法。[在实际开发中用的不多]
  • JSP注释:JSP引擎在将JSP页面翻译成Servlet程序时,忽略JSP页面中被注释的内容。
    • 格式:<%-- 注释信息 --%>或者在<%%>中使用java规定的注释。
    • 注:HTML注释格式:<!-- 注释信息 -->,这个在翻译的Servlet中是有显示的,只是控制显示不显示而已。
  • JSP指令

    • JSP指令是为了JSP引擎(Tomcat)而设计的,它们并不直接产生任何可见的输出,而只是告诉引擎如何处理JSP页面中的其余部分。
    • JSP指令的基本语法格式:<%@ 指令 属性名="值" %>,举例:<%@page import="com.hsx.Student"%>
    • 如果一个指令有多个属性,着多个属性可以写在一个指令中,也可以分开写。
    <!-- 写成多个 -->
    <%@page import="com.hsx.Student"%>
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    
    <!-- 写成一个 -->
    <%@page import="com.hsx.Student" language="java" import="java.util.*" pageEncoding="UTF-8"%>
    • 常用指令:
    • page指令:用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它的作用都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。

      • 属性:

        • language:指示该JSP页面所使用的脚本语言,目前只能是JAVA。
        • extends:指示该JSP生成的Servlet继承的父类是谁。大家不要改。
        • import:在JSP中java脚本中需要用的类,导入该类
          如果导入多个类,比如java.util.List 和java.util.ArrayList
          <%@page import=”java.util.List,java.util.ArrayList”%>
          或者
          <%@page import=”java.util.List”%>
          <%@page import=”java.util.ArrayList”%>
          JSP引擎会自动导入下面的包:
          import javax.servlet.*;
          import javax.servlet.http.*;
          import javax.servlet.jsp.*;//JSP的包
        • session:true|false,默认为true,作用就是是否创建session对象。true时会创建session对象
        • buffer:jsp输出的缓存。none,表示不要缓存;8kb,这是默认值,一般情况不需要修改,或者指定大小的缓存,单位是kb。
        • autoFlush:缓存满后自动刷新。true|false,默认是true
        • isThreadSafe:该JSP是否是线程安全的。true|false
          默认值是true:不安全的
          false:线程安全的
          该属性实际上就是指示JSP对应的Servlet类是否实现SingleThreadModel接口
        • errorPage:指示错误页面是谁。如果路径以”/”开头,并不代表应用名称
          也可以通过web.xml配置全局错误页面
        <error-page>
            <!-- 异常类型 -->
            <exception-type>java.lang.Throwable</exception-type>
            <location>/errors/error.jsp</location>
        </error-page>
        <error-page>
            <!-- 针对响应错误码 -->
            <error-code>404</error-code>
            <location>/errors/404.jsp</location>
        </error-page>

        errorPage属性优先于web.xml中配置的错误页面

        • isErrorPage:true|false(默认值),当前页面是否是错误处理页面。实际上是指对应的Servlet中加不加入Exception对象。
        • contentType=”text/html;charset=UTF-8”:指示页面显示的MIME类型和编码。(给客户端)
        • pageEncoding=”UTF-8”:告知引擎用什么编码来翻译(serlvet)该JSP文件
        • isELIgnored=true|false:是否忽略EL表达式。true是忽略,false不会略
    • include指令:

      • 用于引入其他JSP页面,如果使用include指令引入其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个Servlet,include指令引入通常也称之为静态引入,下面给出静态引入的图介绍:
      • 动态引入request.getRequestDispatcher("demo1.jsp").include(request, response);,生成两个单独的.java文件,然后把两个运行的结果包含在一起,下面给出动态引入的图介绍:
      • 语法:<%@ include file="被包含组件的绝对URL或者相对URL" %>其中file属性用于指定被引入文件的路径,路径以”/”开头,表示代表当前web应用。
      • 细节:
      • 被引入的文件必须遵循JSP语法。
      • 被引入的文件可以使用任意的扩展名,即时其扩展名是html,JSP引擎会按照处理jsp页面的方式处理它里面的内容,为了见名知意,JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。
      • 由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个Servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。
    • taglib指令:用户引入JSP页面中导入标签库,格式:<%@ taglib uri="http://xxx" prefix="s"%>,比如引入Struts2中的OGNL:<%@ taglib prefix="s" uri="/struts-tags" %>

JSP中文乱码

  • 解决方案:第一步,统一默认编码UTF-8;第二步,在*.jsp文件上加page指令:<%@ page pageEncoding="UTF-8" %>

JSP运行原理和九大内置对象

  • 每个JSP页面在第一次被访问时,Web容器都会把请求交给JSP引擎(一个Java程序)去处理》JSP引擎先将JSP翻译成一个_jspServlet(实质上也是有一个servlet),然后按照servlet的调用方式调用。
  • 由于JSP第一次访问时会翻译成Servlet,所以第一次访问通常会比较慢,但是第二次访问,JSP引擎如果发现JSP没有变化,就不再翻译,而是直接调用,所以程序的执行效率不会受到影响。
  • JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用。JSP技术的设计者为了便于开发人员在编写JSP页面时获得这些Web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得者9个对象的引用。
  • 九大内置对象:
    • request – 请求对象HttpServletRequest
    • response – 响应对象HttpServletResponse
    • config – ServletConfig
    • application – ServletContext
    • exception – 异常对象(isErrorPage必须为true)
    • session – HttpSession
    • page – this,代表当前的Servlet对象
    • out – 输出对象JspWriter(作用同于PrintWriter) *
    • pageContext – PageContext对象 *
  • out内置对象:
    • out内置对象用于向客户端发送文本数据。
    • out对象通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
    • JSP页面中的out内置对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
    • 只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回PrintWriter对象将out的缓存区中的内容真正写入到Servlet引擎提供的缓存区中。
out.println("a<br/>");
response.getWriter().println("b<br/>");

上面的输出的结果是先b再a,如果想先输出a再输出b,可以采用关闭缓存或者out.flush();使得缓存满。

  • pageContext对象:
    • pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不尽封装了对其它8个内置对象的引用,它自身还是一个域对象,可以用来保存数据,并且,这个对象还封装了web开发中经常涉及到的一些常用的操作,例如引入和跳转其它资源、检索其它域对象中的属性等。
    • 通过pageContext获得其它对象:
    • getException方法返回exception内置对象
    • getPage方法返回page内置对象
    • getRequest方法返回request内置对象
    • getResponse方法返回response内置对象
    • getServletConfig方法返回config内置对象
    • getServletContext方法返回application内置对象
    • getSession方法返回session内置对象
    • getOut方法返回out内置对象。
    • pageContext封装其他8个内置对象的意义:把pageContext对象传递给一个普通java对象。
public class Demo 

    public void method(PageContext pageContext) 
        ServletRequest request = pageContext.getRequest();
        ServletResponse response = pageContext.getResponse();
    
  • forward():
pageContext.forward("demo1.jsp");

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

<jsp:forward page="demo1.jsp"/>
  • include():
pageContext.include("demo1.jsp");

request.getRequestDispatcher("demo1.jsp").include(request, response);

<%@ include file="demo1.jsp"%>  //只有这一种才是静态包含

<jsp:include page="demo1.jsp"></jsp:include>
  • pageContext对象中常用的方法
// 针对page范围的域对象绑定、获取、删除
public void setAttribute(java.lang.String name, java.lang.Object value);
public java.lang.Object getAttribute(java.lang.String name);
public void removeAttribute(java.lang.String name); 

// pageContext对象中还封装了访问其他域的方法
public void setAttribute(java.lang.String name, java.lang.Object value, int scope);
public java.lang.Object getAttribute(java.lang.String name, int scope);
public void removeAttribute(java.lang.String name, int scope);

// 代表各个域的常量
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE

// 依次从page、request、session、application范围内获取搜寻指定的参数
findAttribute() 

JSP页面图片下载

图片下载必须使用到字节流,但是JSP页面有内置对象out,out又可以看成PrintWriter,其实字符流,而在Servlet中不允许同时存在字节流和字符流,则需要把JSP页面调用的out内置对象的所有行删除,注意一个空行或者一个空格都调用了out内置对象。

<%@page import="java.io.OutputStream"%><%@page import="java.io.FileInputStream"%><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%
  String realPath = application.getRealPath("/img/p1.jpg");
  FileInputStream fis = new FileInputStream(realPath);
  OutputStream os = response.getOutputStream();

  //通知客户端的下载的方式
  response.setHeader("Content-Disposition", "attachment;filename=p1.jpg");
  byte[] buffer = new byte[1024];
  int len = -1;
  while ((len = fis.read(buffer)) != -1) 
      os.write(buffer, 0, len);
  
  fis.close();

  %>

JSP标签

JSP标签页称为JSP Action(JSP动作)元素,它用于在JSP页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成JSP页面难以维护。常用的JSP标签:

  • <jsp:include>标签:用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入。语法:<jsp:include page="relativeURL | <%=expression%>" flush="true|false"/>
    • page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
    • flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。
  • <jsp:forward>标签:用于把请求转发给另外资源。语法:<jsp:forword page="relativeURL | <%=expression%>"/>
    • page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式获得。
  • <jsp:param>标签:当使用<jsp:include><jsp:forward>标签引入或将请求转发给其他资源时,可以使用<jsp:param>标签向这个资源传递参数。

JSP映射

由于JSP实际上就是一个Servlet,那么可以像配置Servlet映射那样配置来映射JSP。

    <servlet>
        <servlet-name>HelloWorld</servlet-name>
        <jsp-file>/demo1.jsp</jsp-file>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/demo1.html</url-pattern>
    </servlet-mapping>

JSP页面调错

根据页面的信息,找到对应已经翻译成的Servlet,查看错误的原因。

4大域对象

  • page PageContext 当前页面
  • request HttpServletRequest 请求范围,只要响应了,就结束
  • session HttpSession 会话范围,session立刻失效或超时,就结束
  • application ServletContext 应用范围,web重新加载或者停止,就结束

JavaBean

JavaBean是一个遵循特定写法的Java类,它通常有以下特点:
- 这个Java类必须具有一个无参的构造方法。
- 字段必须私有化。
- 私有化的字段必须通过public类型的方法[getter/setter]暴露给其它程序,并且方法的命名也必须遵守一定的命名规范。
- 实现Serialiazable接口,便于序列化和反序列化。

JavaBean在JavaEE开发中,通常用于封装数据,对于遵循以上写法的JavaBean组件,其它程序可以通过反射技术实例化JavaBean对象,并且通过反射那些遵循命名规范的方法,从而获知JavaBean的属性,进而调用其属性保存数据。
- 封装对象
- 表示实际业务的某些名词(实际/抽象)。

在JSP中使用JavaBean

JSP技术提供了三个关于JavaBean组件的动作元素 [内置JSP标签],分别是:

  • <jsp:useBean>标签:用于在JSP页面中的域范围内查找或实例化一个JavaBean对象。
    • 如果存在则直接返回该JavaBean对象的引用。
    • 如果不存在则实例化一个新的JavaBean对象并将它指定的名称存储到指定的域范围中。
    • 常用语法<jsp:useBean id="beanName" class="package.class" scope="page | request | session | application"><jsp:useBean>
    • id属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
    • class属性用于指定JavaBean的完整类名(即必须带有包名)。
    • scope属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page/request/session/application等四个值中的一个(其默认的是page)。
  • <jsp:setProperty>标签:用于在JSP页面中设置一个JavaBean对象的属性,前提Bean存在。
  • <jsp:getProperty>标签:用于在JSP页面中获取一个JavaBean对象的属性,前提Bean存在。
<jsp:useBean id="hh" class="com.hsx.Student" scope="page"></jsp:useBean>
<%=hh.getName() %>
<%=hh.getId() %>
<jsp:setProperty property="id" name="hh" value="23"/>
<jsp:setProperty property="name" name="hh" value="皇后搜寻"/>
<jsp:getProperty property="id" name="hh"/>
<jsp:getProperty property="name" name="hh"/>
<%=hh.getName() %>
<%=hh.getId() %>
<jsp:setProperty property="id" name="hh" param="id"/>
<jsp:setProperty property="name" name="hh" param="id"/>
<jsp:setProperty property="*" name="hh"/>

EL表达式

获取数据

  • 使用El表达式获取数据语法:”$标识符”
  • EL表达式语句在执行是,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、session、application四个域中查找相应的对象,找到则返回相应的对象,找不到则返回”“(注意,不是null,而是空字符串)。
<jsp:useBean id="s" class="com.hsx.Student" scope="page"></jsp:useBean>
$s.name 
<br/>
<jsp:getProperty property="name" name="s"/>
<br/>
<%
Object o = pageContext.findAttribute("s");
Student student = (Student) o;
out.println(student.getName());
%>    
<br/>
$o 

上面的代码$o 中的o没有存放在域中,那么在浏览器上显示的是”“.。

  • EL表达式也可以很轻松获取JavaBean的属性,或获取数组、Collection、Map类型的数据[$user.address.city,$user.list[0],$map.key]
<%
Student student = new Student();
student.setName("你好");
Address address = new Address();
address.setProvince("安徽");
address.setCity("黄山");
student.setAddress(address);
request.setAttribute("student", student);
%>
$student.name 
$student.address.city 

<hr/>

<%
List<String> list = new ArrayList<String>();
list.add("11");
list.add("22");
request.setAttribute("list", list);
%>
$list[1] 

<hr/>

<% 
Map<String, String> map = new HashMap<String, String>();
map.put("one", "111");
map.put("two", "222");
request.setAttribute("map", map);
%>
$map.one 
  • 结合JSTL的foreach标签,使用EL表达式也可以很轻松迭代各种类型的数组或集合[迭代数组、迭代colleation类型集合、迭代map类型集合]

  • empty运算符:检查对象是否为null或空,当对象不存在null或空字符串或空集合或空数组,$empty xx 都打印true

<%
Student s = new Student();
request.setAttribute("s", s);
%>
$empty s 
  • 二元表达式:$user != null ? user.name : ""
$student.gender == 1 ? "男""女"

获取web开发常用对象

  • El表达式语言中定义了11个隐含对象,使用这些隐含对象可以很方便地获取web开发中的一些常用对象,并读取这些对象的数据。语法:$隐式对象名称 获取对象的引用。
    • pageContext:代表JSP中pageContext对象,获取其他8个内置对象。
    • pageScope:代表page域中的对象
    • requestScope:代表request域中的对象
    • sessionScope:代表session域中的对象
    • applicationScope:代表application域中的对象
    • param:Map对象,保存了所有请求参数的Map对象,http地址传过来的参数http://localhost:8080/jsp/el.jsp?username=hsx,$param.username
    • paramValues:表示一个保存了所有请求参数的Map对象,它对于某个请求参数,返回的是一个String[],Httphttp地址传过来的参数http://localhost:8080/jsp/el.jsp?username=hsx&username=hhh,$paramValues.username[0]
    • header:Map对象,获取一个请求头的值,$header.accept ,当其中的请求头中有-隔开的请求头,那么$header["Accept-language"]
    • headerValues:表示一个保存了所有请求头中的Map对象,它对于某个请求头,返回的是一个String[]。
    • cookie:表示一个保存了所有cookie的Map对象(value对应一个cookie值)。
    • initParam:表示一个保存了所有web应用初始化参数[web.xml]的map对象。

使用El调用Java方法

EL表达式语法允许开发人员开发自定义函数,以调用Java类的方法。

  • 示例:$prefix: method(params)
  • 在EL表达式中调用的只能是Java类的静态方法。
  • 这个Java类的静态方法需要在TLD文件中描述,才可以被EL表达式调用。
  • EL自定义函数用于扩展EL表达式的功能,可以让EL表达式完成普通的Java程序代码所能完成的功能。
  • EL自定义函数开发与应用包括以下三个步骤:
    1. 编写一个Java类的静态方法
    2. 编写标签库描述(tld)文件,在tld文件中描述自定义函数
    3. 在JSP页面中导入和使用自定义函数。
//-------------编写一个Java类的静态方法--------------------------
public class Small2Big 

    public static String toUpperCase(String value) 

        return value.toUpperCase();
    


//--------编写标签库描述(tld)文件,在tld文件中描述自定义函数(放在工程下的WEB-INF目录下)--------
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
  version="2.0">

  <tlib-version>1.0</tlib-version>
  <jspversion>1.1</jspversion>

  <description>myfun</description>
  <short-name>hsx</short-name>
  <uri>http://www.hsx.com/jsp/jstl/myfun</uri>

  <function>
    <description>toUpperCase</description>
    <name>toUpperCase</name>
    <function-class>com.hsx.Small2Big</function-class>
    <function-signature>java.lang.String toUpperCase(java.lang.String)</function-signature>
    <example>&lt;hsx:toUpperCase('aaa')</example>
  </function>

</taglib>

//-----------在JSP页面中导入和使用自定义函数----------
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="hsx" uri="http://www.hsx.com/jsp/jstl/myfun" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <title></title>

    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    

  </head>

  <body>

    $hsx:toUpperCase('aaa') 

  </body>
</html>

JSTL

  1. 要引入两个jar包:jstl.jar和standard.jar
  2. 在JSP页面中加上<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>元素导入标签库。

    • 简单练习下jstl中的core[核心包]
<!-- list -->
<%
    List<Student> list = new ArrayList<Student>();
    list.add(new Student(1, "aaa"));
    list.add(new Student(2, "bbb"));
    list.add(new Student(3, "ccc"));
    list.add(new Student(4, "ddd"));
    list.add(new Student(5, "eee"));
    request.setAttribute("list", list); //存放在request域中
%>
<table border="1" width="50%">
    <tr>
        <th>序号</th>
        <td>ID</td>
        <td>NAME</td>
    </tr>
    <c:forEach items="$list " var="student" varStatus="s">
        <tr style="background-color: $s.count % 2 == 0 ? 'red' : 'yellow' ">
            <td>$s.count </td>
            <td>$student.id </td>
            <td>$student.name </td>
        </tr>
    </c:forEach>
</table>
<hr/>

<!-- map -->
<%
Map<String, Student> map = new HashMap<String, Student>();
map.put("a", new Student(1, "aaa"));
map.put("b", new Student(2, "bbb"));
map.put("c", new Student(3, "ccc"));
map.put("d", new Student(4, "ddd"));
map.put("e", new Student(5, "eee"));
request.setAttribute("map", map);
%>
<c:forEach items="$map " var="st">
    $st.key =$st.value.name :$student.value.id 
</c:forEach>
<hr/>

<!-- if --> 
<%
session.setAttribute("stud", new Student(1, "hsx"));
%>
<c:if test="$sessionScope.stud == null ">
    <input type="text" name=""/>登录
</c:if>
<c:if test="$sessionScope.stud != null ">
    欢饮您!$sessionScope.stud.name 
</c:if>

以上是关于JSP简单介绍的主要内容,如果未能解决你的问题,请参考以下文章

JSP中的EL语言

jsp内置对象的作用范围

JAVA-JSP内置对象之request范围

jsp内置对象 的使用范围和类型说明

JSP基础--九大内置对象

jsp动作标签