Javaweb之jsp详解

Javaweb之jsp详解

1. JSP指令元素

1.1. page指令

page指令是JSP页面中最常用的指令,用来声明JSP页面的属性等信息。一个page指令允许定义多个属性;也可以一个page指令定义一个属性,定义多个page指令。

<!-- 一个page指令,设置多个属性 -->
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!-- 一个page指令,设置一个属性.配置多个page指令 -->
<%@ page import="java.util.*"%>
<%@ page pageEncoding="UTF-8"%>

但是需要注意的是:

  • page指令设置的属性只能出现一次,除import属性以外。
  • 属性名称区分大小写。

page指令允许的属性如下:

属性名称取值范围描述
languagejava指明该JSP文件采用的语言。
extends任何类的全名指明该JSP文件继承于哪个类。JSP为Servlet,因此当指明继承普通类时需要实现Servlet的init()、destroy()等方法。
import任何包名、类名引入该JSP中用到的类、包等。import是唯一可以声明多次的page指令属性。一个import属性可以引用多个类,中间用英文逗号隔开。JSP中下面四个包里的类可以直接使用:java.lang.,javax.servlet.,javax.servlet.jsp.,javax.servlet.http.
sessiontrue,false指明该JSP内是否内置Session对象。如果为true,则内置Session对象,可直接使用。否则不内置Session对象。默认为true
autoFlushtrue,false是否运行缓存。如果为true,则使用out.println()等方法输出的字符串并不是立刻到达服务器端的,而是暂时存在缓存里,缓存满或者程序执行完毕或者执行out.flush()操作时才到客户端。默认为true
buffernone、数字+KB指定缓存大小,当autoFlush设为true时有效,默认值为8KB。
isThreadSafetrue,false指定是否线程安全。如果为true,则运行多个线程同时运行该JSP程序,否则只运行一个线程运行,其余线程等待。默认为false
isErrorPagetrue,false指定该页面是否为错误处理页面。如果为true,则该JSP内置Exception对象,可直接使用,否则没有。默认为false
errorPage某个JSP页面的相对路径指明一个错误显示页面,如果该JSP程序抛出一个未捕捉的异常,则转到errorPage指定的页面。errorPage指定的页面通常isErrorPage属性为true,且内置Exception对象为未捕捉的异常。
contentType有效的文档类型客户端浏览器根据该属性判断文档类型。
info任意字符串指明该JSP的信息,该信息可以通过Servlet.getServletInfo()方法获取。
trimDirective Whitespacestrue,false是否去掉指令前后的空白字符。默认为false
isELIgnoredtrue,false指明当前页面是否忽略EL表达式。默认为false,表示不忽略。
  • pageEncoding

    contentType

    属性

    • pageEncoding属性:指明当前JSP页面使用的编码格式。pageEncoding属性的值要与JSP页面的真实编码保持一致,否则会出现乱码。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    • contentType属性:在JSP页面编译成Servlet文件时,对应response.setContentType()方法。

pageEncoding属性与contentType属性只设置其中一个属性时,另一个属性的默认与设置的相同。如果两个属性都不设置的话,两个属性的默认值都为“ISO-8859-1”。一般情况下,至少设置其中一个。

  • errorPage

    isErrorPage

    属性

    • 创建一个JSP页面,编写代码如下:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'page.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="expires" content="0">
  </head>
  <body>
    This is my JSP page. <br>
    <%
        if(true){
            throw new RuntimeException();
        }
    %>
  </body>
</html>

[复制代码](javascript:void(0)😉

    • 发布Web工程,并访问http://localhost:8080/jsp/01_directive/page.jsp。

页面访问报错,提示JSP页面的throw new RuntimeException();这句报错。当页面报错时,是不希望用户看到这样的错误页面,而是友好的错误信息。

    • 创建一个JSP页面,用于页面报错的友好提示信息。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'error.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    this is error page.<br>
  </body>
</html>

[复制代码](javascript:void(0)😉

    • 在第一个JSP页面中增加如下代码,设置如果当前页面出现错误,利用error.jsp页面进行错误信息的提示。
<%@ page language="java" pageEncoding="UTF-8" errorPage="error.jsp"%>
    • 重新发布Web工程,并访问http://localhost:8080/jsp/01_directive/page.jsp。

这时再次访问当前的JSP页面,会发现显示的是error.jsp页面的内容。这样的处理使得报错更好友,但是还存在一个问题,就是通过HttpWatch工具抓取会发现响应状态码为200,并不是错误的状态码。这就说明了虽然页面报错并进行了相关提示,但实际上JSP页面将错误隐藏起来,这样不利于之后的处理。

    • 在error.jsp页面中增加如下代码,设置如果当前JSP页面错误,响应对应的状态码,以便之后处理。
<%@ page language="java" pageEncoding="UTF-8" isErrorPage="true"%>
    • 重新发布Web工程,并访问http://localhost:8080/jsp/01_directive/page.jsp。
    • 在error.jsp页面中,可以使用JSP内置对象exception获取异常信息等功能,该对象只能在错误页面中。

[复制代码](javascript:void(0)😉

<%@ page language="java" pageEncoding="UTF-8" isErrorPage="true"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'error.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    this is error page.<br>
    <%=exception.getMessage() %>
  </body>
</html>

[复制代码](javascript:void(0)😉

    • 在JSP页面中指定错误页面虽然可以,但是操作繁琐(实际开发要为每一个JSP页面指定)。还可以使用web.xml文件配置错误页面信息。

[复制代码](javascript:void(0)😉

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    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-app_2_5.xsd">
  <!-- 配置对应状态码为404的错误页面 -->
  <error-page>
      <!-- 设置对应的状态码 -->
      <error-code>404</error-code>
      <!-- 配置错误页面路径 -->
      <location>/directive/error.jsp</location>
  </error-page>
  <!-- 配置对应异常的错误页面 -->
  <error-page>
      <!-- 设置对应的异常 -->
      <exception-type>java.lang.RuntimeException</exception-type>
      <!-- 配置错误页面路径 -->
      <location>/directive/error.jsp</location>
  </error-page>
</web-app>

[复制代码](javascript:void(0)😉

1.2. include指令

include指令用于在JSP页面中静态包含另一个文件,该文件可以是JSP页面、HTML页面、文本文件或一段Java代码。include语法格式如下:

<%@ include file="包含文件的路径" %>

设置包含文件的路径只能是常量,不能是变量。

include.jsp页面:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'include.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
      欢迎你,现在的时间是:
    <%@ include file="date.jsp" %>
  </body>
</html>

[复制代码](javascript:void(0)😉

date.jsp页面

<%
    out.println(new java.util.Date().toString());
%>

1.3. taglib指令

JSP页面支持标签,使用标签功能可以实现视图代码重用,很少量的代码可以实现很复杂的显示效果。要使用标签功能必须先声明标签库以及标签前缀。taglib指令用于指明JSP页面使用的JSP标签库。taglib指令的语法格式如下:

<%@ taglib prefix="标签前缀" uri="标签库的完整路径" %>

目前使用最多的是如下标签库:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

2. JSP动作标签

2.1. jsp:include标签

这个动作标签用于在当前页面中包含静态和动态的资源,一旦被包含的页面执行完毕,请求处理将在调用页面中继续进行。这个动作标签与javax.servlet.RequestDispatcher类的include方法一致。

<jsp:include flush="boolean值" page="被包含页面的路径"></jsp:include>
  • flush属性:该属性是可选的。默认值为false,表示当前页面输出使用了缓冲区,在包含之前不刷新缓冲区。true表示刷新缓冲区。
  • page属性:指定被包含资源的相对路径,该路径是相对于当前JSP页面的URL。

include标签与include指令的区别:

语法相对路径发生时间包含的对象描述
<%@ include file=”url”%>相对于当前文件转换期间静态包含的内容被JSP容器分析
<jsp:include page=”url”>相对于当前页面请求处理期间静态和动态包含的内容不进行分析

2.2. jsp:forward标签

这个动作标签运行在运行时将当前的请求转发给一个静态的资源、JSP页面或者Servlet,请求被转向到的资源必须位于同JSP发送请求相同的上下文环境中。这个动作标签与javax.servlet.RequestDispatcher类的forward()方法的作用相同。

这个动作标签的语法格式如下:

<jsp:forward page="请求转发到页面的路径"></jsp:forward>

具体用法如下:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'forward.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
      <h1>forward.jsp</h1>
      <% System.out.println("forward jsp start..."); %>
    <jsp:forward page="include.jsp?flag=true"></jsp:forward>
    <% System.out.println("forward jsp end..."); %>
  </body>
</html>

[复制代码](javascript:void(0)😉

转换成Servlet后的代码

[复制代码](javascript:void(0)😉

out.write("  \t<h1>forward.jsp</h1>\r\n");
out.write("  \t");
System.out.println("forward jsp start..."); 
out.write("\r\n");
out.write("    ");
if (true) {
   _jspx_page_context.forward("include.jsp?flag=true");
   return;
}
out.write("\r\n");
out.write("    ");
System.out.println("forward jsp end..."); 

[复制代码](javascript:void(0)😉

2.3. jsp:param标签

这个动作标签与jsp:include标签、jsp:forward标签配合使用,以键值对形式为其他标签提供参数内容。这个动作标签的语法格式如下:

<jsp:param value="参数值" name="参数名称"/>

具体用法参考如下代码:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'forward.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <jsp:forward page="include.jsp">
        <jsp:param value="true" name="flag"/>
    </jsp:forward>
  </body>
</html>

[复制代码](javascript:void(0)😉

3. JSP内置对象

3.1. out输出流对象

内置对象out是javax.servlet.jsp.JspWriter类的实例,与response.getWriter()方法的作用相同,都是服务器端向客户端输出的字符串内容。该对象的常用方法如下:

Method Summary
abstract voidclear() Clear the contents of the buffer.
abstract voidflush() Flush the stream.
intgetBufferSize() This method returns the size of the buffer used by the JspWriter.
abstract intgetRemaining() This method returns the number of unused bytes in the buffer.
booleanisAutoFlush() This method indicates whether the JspWriter is autoFlushing.
abstract voidprint(String s) Print a string.
abstract voidprintln(String x) Print a String and then terminate the line.

3.2. pageContext上下文对象

内置对象pageContext是javax.servlet.jsp.PageContext类的实例,该对象是JSP的四大作用域对象之一,pageContext对象代表当前JSP页面编译后的内容,多用于JSP页面之间共享数据内容。

  • pageContext对象的常用方法
Method Summary
abstract ObjectgetAttribute(String name) Returns the object associated with the name in the page scope or null if not found.
abstract voidremoveAttribute(String name) Remove the object reference associated with the given name from all scopes.
abstract void[setAttribute](https://www.cnblogs.com/aaron911/p/7799265.html#setAttribute(java.lang.String, java.lang.Object))(String name, Object value) Register the name and value specified with page scope semantics.
  • pageContext对象获取其他八个内置对象
Method Summary
abstract JspWritergetOut() The current value of the out object (a JspWriter).
abstract ExceptiongetException() The current value of the exception object (an Exception).
abstract ObjectgetPage() The current value of the page object (In a Servlet environment, this is an instance of javax.servlet.Servlet).
abstract ServletRequestgetRequest() The current value of the request object (a ServletRequest).
abstract ServletResponsegetResponse() The current value of the response object (a ServletResponse).
abstract ServletConfiggetServletConfig() The ServletConfig instance.
abstract ServletContextgetServletContext() The ServletContext instance.
abstract HttpSessiongetSession() The current value of the session object (an HttpSession).
  • pageContext对象操作其他三个域
Method Summary
abstract ObjectfindAttribute(String name) Searches for the named attribute in page, request, session (if valid), and application scope(s) in order and returns the value associated or null.
abstract Object[getAttribute](https://www.cnblogs.com/aaron911/p/7799265.html#getAttribute(java.lang.String, int))(String name, int scope) Return the object associated with the name in the specified scope or null if not found.
abstract void[removeAttribute](https://www.cnblogs.com/aaron911/p/7799265.html#removeAttribute(java.lang.String, int))(String name, int scope) Remove the object reference associated with the specified name in the given scope.
abstract void[setAttribute](https://www.cnblogs.com/aaron911/p/7799265.html#setAttribute(java.lang.String, java.lang.Object, int))(String name, Object value, int scope) Register the name and value specified with appropriate scope semantics.

上述方法中的scope参数表示其他三个域常量:

Field Summary
static intAPPLICATION_SCOPE Application scope: named reference remains available in the ServletContext until it is reclaimed.
static intREQUEST_SCOPE Request scope: the named reference remains available from the ServletRequest associated with the Servlet until the current request is completed.
static intSESSION_SCOPE Session scope (only valid if this page participates in a session): the named reference remains available from the HttpSession (if any) associated with the Servlet until the HttpSession is invalidated.

3.3. request请求对象

内置对象request是javax.servlet.ServletRequest类的实例,代表着客户端的请求。具体用法请参考Request对象内容。

3.4. response响应对象

内置对象response是javax.servlet.ServletResponse类的实例,代表着服务器端的响应。具体用法请参考Response对象内容。

3.5. config配置对象

内置对象config是javax.servlet.ServletConfig类的实例,ServletConfig对象封装了配置在web.xml文件中初始化JSP的参数,JSP通过config对象获取这些参数值。具体用法请参考ServletConfig对象内容。

3.6. session会话对象

内置对象session是javax.servlet.http.HttpSession类的实例,session与cookie是解决Http协议的无状态问题的两种解决方案。如果在JSP页面中使用<%@ page session=”false”%>指令的话,则在当前JSP页面中不能使用session内置对象。但一般情况下,不会禁止使用session对象,具体用法请参考HttpSession对象内容。

3.7. application应用对象

内置对象application是javax.servlet.ServletContext类的实例,ServletContext封装了JSP所在的Web应用程序的信息,整个Web应用程序对应一个ServletContext对象。具体用法请参考ServletContext对象内容。

3.8. page页面对象

内置对象page是javax.servlet.jsp.HttpJspPage类的实例,page对象代表当前JSP页面,是当前JSP编译后的Servlet类的对象。page相当于普通Java类中的关键字this。

3.9. exception异常对象

内置对象exception是java.lang.Exception类的实例,该对象封装了JSP中抛出的异常信息。exception对象只能在使用<%@ page isErrorPage=”true”%>指令的JSP页面中。

4. JSP与JavaBean

4.1. JavaBean概述

JavaBean本质上就是一个Java类,只不过这个类需要遵循一些编码的规范。在JSP页面中,既可以使用普通类一样实例化JavaBean类的对象,调用方法,也可以利用JSP提供的动作标签访问JavaBean。

一个标准的JavaBean具有以下几个特性:

  • 是一个公开(public)的类。
  • 有一个默认的无参构造方法。
  • 提供Setter和Getter方法用于设置和获取JavaBean的属性。

换句话讲,只要是符合上述条件的类,都可以看作是JavaBean。下面就是一个JavaBean实例:

[复制代码](javascript:void(0)😉

public class User {
    public String name;
    public Boolean married;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Boolean isMarried() {
        return married;
    }
    public void setMarried(Boolean married) {
        this.married = married;
    }
}

[复制代码](javascript:void(0)😉

4.2. 内省

SUN公司开发了一套API,方便更好地操作JavaBean的属性,这套API被称之为内省(Introspector)。内省的出现有利于对JavaBean的属性操作,减少了代码量,内省依赖于Java的反射。

通过内省来操作JavaBean的属性,具体步骤如下:

  • 通过Class类对象获取BeanInfo实例。
  • 通过BeanInfo实例获取所有属性描述符对象。
  • 通过属性描述符对象操作对应JavaBean的属性。

[复制代码](javascript:void(0)😉

public class Demo {
    @Test
    public void Demo() throws Exception{
        Class c = User.class;
        Object obj = c.newInstance();
        //1 通过Class类对象获取BeanInfo实例
        BeanInfo info = Introspector.getBeanInfo(User.class);
        //2 通过BeanInfo实例获取所有属性描述符对象
        PropertyDescriptor[] pds = info.getPropertyDescriptors();
        /*
         * 3 通过属性描述符对象操作对应JavaBean的属性
         *  * 获取属性名称
         *  * 获取读方法
         *  * 获取写方法
         */
        for (PropertyDescriptor pd : pds) {
            // 获取并输出JavaBean的属性名称
            System.out.println(pd.getName());
            // 获取并输出JavaBean的属性类型
            System.out.println(pd.getPropertyType());
            // 判断当前获取的JavaBean的属性名称是否为"name"
            if (pd.getName().equals("name")) {
                // 获取JavaBean的name属性的写方法
                Method wmd = pd.getWriteMethod();
                wmd.invoke(obj, "longestory");
                // 获取JavaBean的name属性的读方法
                Method rmd = pd.getReadMethod();
                System.out.println(rmd.invoke(obj));
            }
        }
    }
}

[复制代码](javascript:void(0)😉

4.3. BeanUtils工具

虽然Java提供了反射和内省相关的API,用于操作JavaBean组件的属性。但这些API方法使用起来很复杂,BeanUtils工具是Apache基于Java的内省封装的一个工具包。

BeanUtils工具包使用时,需要依赖logging日志包。

  • 通过BeanUtils工具操作JavaBean的属性相关简单了不少。

[复制代码](javascript:void(0)😉

public class Demo {
    @Test
    public void Demo() throws Exception{
        Class c = User.class;
        Object obj = c.newInstance();
        BeanUtils.setProperty(obj, "name", "longestory");
        BeanUtils.setProperty(obj, "age", "14");
        BeanUtils.setProperty(obj, "married", true);
        
        String name = BeanUtils.getProperty(obj, "name");
        System.out.println(name);
    }
}

[复制代码](javascript:void(0)😉

  • 通过BeanUtils工具的populate()方法来操作JavaBean。

[复制代码](javascript:void(0)😉

public class Demo {
    @Test
    public void Demo() throws Exception{
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name", "longestory");
        map.put("age", "18");
        map.put("married", true);
        
        Class c = User.class;
        Object obj = c.newInstance();
        
        BeanUtils.populate(obj, map);
        System.out.println(obj);
    }
}

[复制代码](javascript:void(0)😉

  • 通过populate()方法将一个Map集合内容设置到对应的JavaBean中,自定义一个工具类来完成复用。

[复制代码](javascript:void(0)😉

public class CommonUtils {
    public static <T> T toBean(Map map, Class<T> clazz) {
        try {
            T bean = clazz.newInstance();
            BeanUtils.populate(bean, map);
            return bean;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

[复制代码](javascript:void(0)😉

下面通过一个案例来掌握BeanUtils封装内省的内容。

  • 创建一个JSP页面用于显示用户注册信息。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!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>
    <form action="/12_jsp/regist" method="post">
          用户名:<input type="text" name="username"/><br/>
          密码:<input type="password" name="password"/><br/>
          确认密码:<input type="password" name="repassword"/><br/>
          邮箱:<input type="text" name="email"/><br/>
      <input type="submit" value="注册"/>
    </form>
  </body>
</html>

[复制代码](javascript:void(0)😉

  • 创建一个JavaBean用于封装用户注册信息。

[复制代码](javascript:void(0)😉

public class Person {
    private String username;
    private String password;
    private String email;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    @Override
    public String toString() {
        return "Person [username=" + username + ", password=" + password + ", email=" + email + "]";
    }
}

[复制代码](javascript:void(0)😉

  • 创建一个Servlet用于接收用户注册信息。

[复制代码](javascript:void(0)😉

public class PersonServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Person person = CommonUtils.toBean(request.getParameterMap(), Person.class);
        System.out.println(person);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

[复制代码](javascript:void(0)😉

  • 配置Web工程的web.xml文件。

[复制代码](javascript:void(0)😉

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    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-app_2_5.xsd">
  <display-name></display-name>
  <servlet>
    <servlet-name>PersonServlet</servlet-name>
    <servlet-class>app.java.exam.PersonServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>PersonServlet</servlet-name>
    <url-pattern>/regist</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

[复制代码](javascript:void(0)😉

  • 发布Web工程,并访问http://localhost:8080/jsp/index.jsp进行测试。

4.4. JSP动作标签

在JSP中可以像使用普通类一样访问JavaBean,JSP提供了三个动作标签jsp:useBean、jsp:setProperty和jsp:getProperty来访问JavaBean。

  • jsp:useBean动作标签

该动作标签用于实例化JavaBean,或者定位一个已经存在的JavaBean实例。

该动作标签的语法格式:

<jsp:useBean id="实例名称" class="实例全类名" scope="指定范围"></jsp:useBean>
    • id属性:用于标识JavaBean实例的名称。需要注意的是,指定的名称是区分大小写的,并遵照Java语言变量命名的约定。
    • class属性:指定JavaBean实例的完整类名。
    • scope属性:指定一个范围,在这个范围中,JavaBean实例的引用是可用的,实际上也是指定JavaBean实例的生命周期。备选取值有page、request、session和application,默认值为page。

jsp:useBean动作标签的实际作用可以利用下述Java代码进行解释:

[复制代码](javascript:void(0)😉

<jsp:useBean id="user" class="app.java.bean.User" scope="session" />

User user = (User)session.getAttribute("user");
if(user == null) {
    user = new User();
    session.setAttribute("user", user);
}

[复制代码](javascript:void(0)😉

  • jsp:setProperty动作标签

该动作标签与jsp:useBean一起使用,用于设置JavaBean的属性。

该动作标签的语法格式:

<jsp:setProperty property="属性名称" name="实例名称" value="属性值"/>
  • jsp:getProperty动作标签

该动作标签用于访问一个Bean的属性,并把属性的值转化成一个String,然后发送到输出流中。如果属性是一个对象,将调用该对象的toString()方法。

该动作标签的语法格式:

<jsp:getProperty property="属性名称" name="实例名称"/>

5. EL表达式语言

5.1. EL表达式语法

JSP中可以使用EL(Expression Language)表达式。EL表达式是用“${}”括起来的脚本,用来更方便地读取对象。EL表达式写在JSP的HTML代码中,而不能写在“<%%>”的JSP脚本中。

如果在JSP页面中使用了<%@ page isELIgnored=”true”%>指令的话,该JSP页面会忽略EL表达式。如果忽略某个EL表达式的话,可以在EL表达式之前添加“\”(例如${1+2})。

当EL表达式的值为null时,会在JSP页面上显示空白,即什么都不显示。

EL表达式具有一些运算符,如下表

运算符说明范例结果
+${17+5}22
-${17-5}12
*${17*5}85
/或div 17 / 5 或 {17/5}或 17/5{17 div 5}3
%或mod取余KaTeX parse error: Expected '}', got 'EOF' at end of input: {17%5}或{17 mod 5}2
==或eq等于 5 = = 5 或 {5==5}或 5==5{5 eq 5}true
!=或ne不等于 5 ! = 5 或 {5!=5}或 5!=5{5 ne 5}false
<或lt小于 3 < 5 或 {3<5}或 3<5{3 lt 5}true
>或gt大于 3 > 5 或 {3>5}或 3>5{3 gt 5}false
<=或le小于等于 3 < = 5 或 {3<=5}或 3<=5{3 le 5}true
>=或ge大于等于 3 > = 5 或 {3>=5}或 3>=5{3 ge 5}false
&&或and并且KaTeX parse error: Expected '}', got '&' at position 6: {true&̲&false}或{true and false}false
!或not ! t r u e 或 {!true}或 !true{not true}false
||或or或者 t r u e ∥ ∥ f a l s e 或 {true\|\|false}或 truefalse{true or false}true
empty是否为空 e m p t y “ ” , 可 以 判 断 字 符 串 、 数 据 、 集 合 的 长 度 是 否 为 0 , 为 0 返 回 t r u e 。 e m p t y 还 可 以 与 n o t 或 ! 一 起 使 用 。 {empty “”},可以判断字符串、数据、集合的长度是否为0,为0返回true。empty还可以与not或!一起使用。 empty00trueemptynot!使{not empty “”}true

值得注意的是旧版本的Servlet规范不支持EL表达式,例如Tomcat 4.x以及以前的版本都不支持EL表达式。

EL表达式提供了获取JavaBean对象以及属性的简单方式。某些情况下EL表达式完全可以替代JSP脚本或者JSP行为,例如:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'expression.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <jsp:useBean id="user" class="app.java.bean.User" scope="session" />
    <!-- 相当于session.getArribute("person") -->
    欢迎您,${person}.
    <!-- 相当于person.getAge() -->
    <!-- 也相当于<jsp:getProperty name="person" property="age"> -->
        您的年龄为${person.age}.
  </body>
</html>

[复制代码](javascript:void(0)😉

5.2. EL表达式内置对象

EL表达式不仅可以读取对象,还内置了十一个隐藏对象,这些内置对象无需创建,可以直接使用。而EL表达式中的内置对象中,最重要的是获取四大域相关的内置对象,如下表:

标识符描述示例
pageScope包含apge作用域内变量的Map使用<jsp:useBean id=”user” class=”app.java.bean.User” scope=”page”>声明pageScope范围内的User对象后,${pageScope.user.name}将输出该对象的name属性值
requestScope包含request作用域内变量的Map使用<jsp:useBean id=”user” class=”app.java.bean.User” >声明requestScope范围内的User对象后,${requestScope.user.name}将输出该对象的name属性值。useBean标签默认的作用域为request
sessionScope包含session作用域内变量的Map使用<jsp:useBean id=”user” class=”app.java.bean.User” scope=”session”>声明sessionScope范围内的User对象后,${sessionScope.user.name}将输出该对象的name属性值
applicationScope包含application作用域内变量的Map使用<jsp:useBean id=”user” class=”app.java.bean.User” scope=”applcation”>声明applcation Scope范围内的User对象后,${ applcation Scope.user.name}将输出该对象的name属性值

除了上述获取四大域相关的内置对象以外,还有其他内置对象,但实际使用率并不高。

类别标识符描述示例
请求参数param包含所有参数的Map,可以获取参数,返回String p a r a m . f o o 或 {param.foo}或 param.foo{param[‘foo’]}
paramValues包含所有参数的Map,可以获取参数数组,返回String[]当提交多个参数,例如index.jsp?a=first&a=second,提交的参数a为多个值{“first”, “second”}。使用param只能获取第一个值,而使用paramValues能获取到所有值,${paramValues.a[0]}将输出“first”, ${paramValues.a[1]}将输出“second”
头信息header包含所有头信息的Map,返回String${header.host}可能返回localhost:8080
headerValues包含所有头信息的Map,返回String[]${headerValues.host[0]},当头信息为数组时可以获取多个值。
初始化参数initParam包含所有初始化参数的Map${initParam.encoding}
Cookiecookie包含所有Cookie的Map,key为Cookie的name属性使用<%response.addCookie(new Cookie(“user”, “king”))%>设置Cookie后, c o o k i e . u s e r 返 回 该 C o o k i e , {cookie.user}返回该Cookie, cookie.userCookie{cookie.user.name}返回user,${cookie.user.value}返回king
pageContext包含页面内的变量的Map,包含request、response、page等所有内置对象${pageContext.request.remoteAddr}将返回客户端IP地址,相当于执行<%=pageContext.getRequest().getRemoteAddr()%>

之前在页面中编写请求资源路径时,都是固定内容。在掌握了EL表达式后,可以如下方式编写请求资源路径:

<a href="${pageContext.request.contextPath }/index.jsp">请求</a>

5.3. EL表达式函数

EL函数库是由第三方对EL表达式的扩展,目前学习的EL函数库是由JSTL(关于JSTL会在后面的内容学到)添加的。EL函数库就是定义了一些有返回值的静态方法,然后通过EL表达式调用。当然不只是JSTL可以定义EL函数库,我们也可以自定义EL函数库。

因为EL函数库是第三方提供的,所有要想使用的话,首先需要使用taglib指令引入。

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

JSTL提供的EL函数库包含的函数具体如下:

  • String toUpperCase(String input):将一个字符串转换成大写。
  • String toLowerCase(String input):将一个字符串转换成小写。
  • int indexOf(String input, String substring):检索字符串。
  • boolean contains(String input, String substring):判断一个字符串是否包含另一个字符串。
  • boolean containsIgnoreCase(String input, String substring):判断一个字符串是否包含另一个字符串(忽略大小写)。
  • boolean startsWith(String input, String substring):判断一个字符串是否以另一个字符串开始。
  • boolean endsWith(String input, String substring):判断一个字符串是否以另一个字符串结束。
  • String substring(String input, int beginIndex, int endIndex):按照指定开始位置和结束位置截取字符串。
  • String substringAfter(String input, String substring):截取指定字符后的所有字符串。
  • String substringBefore(String input, String substring):截取指定字符前的所有字符串。
  • String escapeXml(String input):将字符串内容进行转义。
  • String trim(String input):将字符串的前后空格去掉。
  • String replace(String input, String substringBefore, String substringAfter):将一个字符串中的某个字符,利用另一个字符替换。
  • String[] split(String input, String delimiters):将一个字符串利用指定分隔符分割。
  • int length(Object obj):返回指定内容的长度。
  • String join(String array[], String separator):使用指定连接符将数组中的每个元素连接。

下面是上述函数的具体使用方式:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'MyJsp.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
      <%
        String[] strs = {"a", "b","c"};
        List list = new ArrayList();
        list.add("a");
        pageContext.setAttribute("arr", strs);
        pageContext.setAttribute("list", list);
    %>
    
    ${fn:length(arr) }<br/><!--3-->
    ${fn:length(list) }<br/><!--1-->
    ${fn:toLowerCase("Hello") }<br/> <!-- hello -->
    ${fn:toUpperCase("Hello") }<br/> <!-- HELLO -->
    ${fn:contains("abc", "a")}<br/><!-- true -->
    ${fn:containsIgnoreCase("abc", "Ab")}<br/><!-- true -->
    ${fn:contains(arr, "a")}<br/><!-- true -->
    ${fn:containsIgnoreCase(list, "A")}<br/><!-- true -->
    ${fn:endsWith("Hello.java", ".java")}<br/><!-- true -->
    ${fn:startsWith("Hello.java", "Hell")}<br/><!-- true -->
    ${fn:indexOf("Hello-World", "-")}<br/><!-- 5 -->
    ${fn:join(arr, ";")}<br/><!-- a;b;c -->
    ${fn:replace("Hello-World", "-", "+")}<br/><!-- Hello+World -->
    ${fn:join(fn:split("a;b;c;", ";"), "-")}<br/><!-- a-b-c -->
    
    ${fn:substring("0123456789", 6, 9)}<br/><!-- 678 -->
    ${fn:substring("0123456789", 5, -1)}<br/><!-- 56789 -->
    ${fn:substringAfter("Hello-World", "-")}<br/><!-- World -->
    ${fn:substringBefore("Hello-World", "-")}<br/><!-- Hello -->
    ${fn:trim("     a b c     ")}<br/><!-- a b c -->
    ${fn:escapeXml("<html></html>")}<br/> <!-- <html></html> -->
  </body>
</html>

[复制代码](javascript:void(0)😉

我们也可以自定义EL函数库,具体自定义EL函数库的步骤如下:

  • 创建一个Java类,该类包含具有返回值的静态方法。

[复制代码](javascript:void(0)😉

package app.java.el.functions;

public class MyFunctions {
    public static String test() {
        return "自定义EL函数库测试";
    }
}

[复制代码](javascript:void(0)😉

  • 在WEB-INF目录下创建一个“.tld”文件,用于配置自定义EL函数库。

[复制代码](javascript:void(0)😉

<?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>
  <short-name>myfn</short-name>
  <uri>http://www.myfn.com/jsp/functions</uri>

  <function>
    <name>test</name>
    <function-class>app.java.el.functions</function-class>
    <function-signature>String test()</function-signature>
  </function>
</taglib>

[复制代码](javascript:void(0)😉

  • 在JSP页面中添加tagllib指令,导入自定义EL函数库。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="ls" uri="/WEB-INF/myfunctions.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>自定义EL函数库</title>
  </head>
  <body>
    <h1>${ls:test() }</h1>
  </body>
</html>

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”>

1.0
myfn
http://www.myfn.com/jsp/functions

test app.java.el.functions String test() ```

[[外链图片转存中…(img-O7v7tGpX-1644682260189)]](javascript:void(0)😉

  • 在JSP页面中添加tagllib指令,导入自定义EL函数库。

[[外链图片转存中…(img-Sv7Bz5oD-1644682260189)]](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="ls" uri="/WEB-INF/myfunctions.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>自定义EL函数库</title>
  </head>
  <body>
    <h1>${ls:test() }</h1>
  </body>
</html>

[复制代码](javascript:void(0)😉

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值