JavaWeb学习笔记(4)-B站尚硅谷

十、JSP

001-什么是jsp?它有什么用?

JSP(全称 Java Server Pages)是由 Sun 公司专门为了解决动态生成 HTML 文档的技术。

jsp 的主要作用是代替 Servlet 程序回传 html 页面的数据。
因为 Servlet 程序回传 html 页面数据是一件非常繁锁的事情。开发成本和维护成本都极高。

在学习 jsp 技术之前,如果我们要往客户端输出一个页面。我们可以使用 Servlet 程序来实现。
通过 Servlet 输出简单的 html 页面信息都非常不方便。
那我们要输出一个复杂页面的时候,就更加的困难,而且不利于页面的维护和调试。
所以 sun 公司推出一种叫做 jsp 的动态页面技术帮助我们实现对页面的输出繁锁工作。

002-如何创建和访问jsp页面?

(1)创建 jsp 的页面

在这里插入图片描述
在这里插入图片描述

(2)如何访问jsp页面
	jsp 页面和 html 页面一样,都是存放在 web 目录下。访问也跟访问 html 页面一样。

比如:在 web 目录下有如下的文件:
web 目录
a.html 页面 访问地址是 =======>>>>>> http://ip:port/工程路径/a.html
b.jsp 页面 访问地址是 =======>>>>>> http://ip:port/工程路径/b.jsp

003-jsp的本质

jsp 页面本质上是一个 Servlet 程序

当我们第一次访问 jsp 页面的时候。
Tomcat 服务器会帮我们把 jsp 页面翻译成为一个 java 源文件。并且对它进行编译成为.class 字节码程序。
我们打开 java 源文件不难发现其里面的内容是:

在这里插入图片描述

该java类继承了HttpJspBase类。
而HttpJspBase 类,它直接地继承了 HttpServlet 类。
也就是说,jsp 翻译出来的 java 类,它间接了继承了 HttpServlet 类。
也就是说,翻译出来的是一个 Servlet 程序。

总结:通过翻译的 java 源代码我们就可以得到结果:jsp 就是 Servlet 程序。

大家也可以去观察翻译出来的 Servlet 程序的源代码,不难发现。其底层实现,也是通过输出流,把 html 页面数据回传给客户端。

在这里插入图片描述

小结:
从生成的文件我们不难发现一个规则。
a.jsp 翻译成 java 文件后的全名是 a_jsp.java 文件
b.jsp 翻译成 java 文件后的全名是 b_jsp.java 文件

那么 当我们访问 一个 xxx.jsp 文件后 翻译成 java 文件的全名是 xxx_jsp.java 文件
xxx_jsp.java 文件是一个 Servlet 程序。原来 jsp 中的 html 内容都被翻译到 Servlet 类的 service 方法中原样输出

index.jsp对应的java文件:

package org.apache.jsp;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.jsp.*;

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {
    
    

  private static final jakarta.servlet.jsp.JspFactory _jspxFactory =
          jakarta.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    
    
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("jakarta.servlet");
    _jspx_imports_packages.add("jakarta.servlet.http");
    _jspx_imports_packages.add("jakarta.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile jakarta.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    
    
    return _jspx_dependants;
  }

  public java.util.Set<java.lang.String> getPackageImports() {
    
    
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    
    
    return _jspx_imports_classes;
  }

  public jakarta.el.ExpressionFactory _jsp_getExpressionFactory() {
    
    
    if (_el_expressionfactory == null) {
    
    
      synchronized (this) {
    
    
        if (_el_expressionfactory == null) {
    
    
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    
    
    if (_jsp_instancemanager == null) {
    
    
      synchronized (this) {
    
    
        if (_jsp_instancemanager == null) {
    
    
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
    
    
  }

  public void _jspDestroy() {
    
    
  }

  public void _jspService(final jakarta.servlet.http.HttpServletRequest request, final jakarta.servlet.http.HttpServletResponse response)
      throws java.io.IOException, jakarta.servlet.ServletException {
    
    

    if (!jakarta.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
    
    
      final java.lang.String _jspx_method = request.getMethod();
      if ("OPTIONS".equals(_jspx_method)) {
    
    
        response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
        return;
      }
      if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
    
    
        response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
        return;
      }
    }

    final jakarta.servlet.jsp.PageContext pageContext;
    jakarta.servlet.http.HttpSession session = null;
    final jakarta.servlet.ServletContext application;
    final jakarta.servlet.ServletConfig config;
    jakarta.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    jakarta.servlet.jsp.JspWriter _jspx_out = null;
    jakarta.servlet.jsp.PageContext _jspx_page_context = null;


    try {
    
    
      response.setContentType("text/html;charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\n");
      out.write("\n");
      out.write("<html>\n");
      out.write("  <head>\n");
      out.write("    <title>$Title$</title>\n");
      out.write("  </head>\n");
      out.write("  <body>\n");
      out.write("  $END$\n");
      out.write("  </body>\n");
      out.write("</html>\n");
    } catch (java.lang.Throwable t) {
    
    
      if (!(t instanceof jakarta.servlet.jsp.SkipPageException)){
    
    
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
    
    
            if (response.isCommitted()) {
    
    
              out.flush();
            } else {
    
    
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {
    
    }
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
    
    
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

index.jsp:
在这里插入图片描述

004-jsp语法

(1)jsp 文件头部 page 指令

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

这是 jsp 文件的头声明。表示这是 jsp 页面

language 属性 		表示 jsp 翻译后是什么语言文件。暂时只支持 java。
contentType 属性 	表示 jsp 返回的数据类型是什么。也是源码中 response.setContentType()参数值
pageEncoding 属性 	表示当前 jsp 页面文件本身的字符集
import 属性 			跟 java 源代码中一样。用于导包,导类。

========================两个属性是给 out 输出流使用=============================

autoFlush 属性 		设置当 out 输出流缓冲区满了之后,是否自动刷新冲级区。默认值是 true
buffer 属性 			设置 out 缓冲区的大小。默认是 8k

============================================================================

errorPage 属性 		设置当前 jsp 发生错误后,需要跳转到哪个页面去显示错误信息
	errorPage 表示错误后自动跳转去的路径,这个路径一般都是以斜杠打头,
	它表示请求地址为 http://ip:port/工程路径/,映射到IDEA的 Web 目录


isErrorPage 属性 	设置当前 jsp 页面是否是错误信息页面。默认是 false。如果是 true 可以获取异常信息。
session 属性 		设置访问当前 jsp 页面,是否会创建 HttpSession 对象。默认是 true。
extends 属性 		设置 jsp 翻译出来的 java 类默认继承谁

(2)jsp 中的三种脚本

1)声明脚本(极少使用):

声明脚本的格式是: <%! 声明 java 代码 %>
作用:可以给 jsp 翻译出来的 java 类定义属性和方法甚至是静态代码块。内部类等。

在这里插入图片描述
在这里插入图片描述

2)表达式脚本(常用):

表达式脚本 用于向页面输出内容

表达式脚本的格式是:<%=表达式%>

练习:
1. 输出整型
2. 输出浮点型
3. 输出字符串
4. 输出对象

在这里插入图片描述

扫描二维码关注公众号,回复: 14132632 查看本文章
表达式脚本的特点:
1、所有的表达式脚本都会被翻译到_jspService() 方法中
2、表达式脚本都会被翻译成为 out.print()输出到页面上
3、由于表达式脚本翻译的内容都在_jspService() 方法中,所以_jspService()方法中的对象都可以直接使用。
4、表达式脚本中的表达式不能以分号结束。

3)代码脚本:
在这里插入图片描述
在这里插入图片描述

代码脚本的特点是:
1、代码脚本翻译之后都在_jspService 方法中
2、代码脚本由于翻译到_jspService()方法中,所以在_jspService()方法中的现有对象都可以直接使用。
3、还可以由多个代码脚本块组合完成一个完整的 java 语句。如下

在这里插入图片描述

4、代码脚本还可以和表达式脚本一起组合使用,在 jsp 页面上输出数据

在这里插入图片描述

(3)jsp 中的三种注释

1. html注释:

<!-- 这是 html 注释 -->

html 注释会被翻译到 java 源代码中。在_jspService 方法里,以 out.writer

2. java注释:

java注释一般写在脚本中,给写的java代码进行注释

<%
// 单行 java 注释
/* 多行 java 注释 */
%>

java 注释会被翻译到 java 源代码中

3. jsp注释:

<%-- 这是 jsp 注释 --%>

jsp 注释可以注掉,jsp 页面中所有代码。

005-jsp 九大内置对象

jsp 中的内置对象,是指 Tomcat 在翻译 jsp 页面成为 Servlet 源代码后,翻译后的java代码中提供的九大对象,叫内置对象。

在这里插入图片描述

006-jsp 四大域对象

四个域对象分别是:
	pageContext (PageContextImpl 类) 	当前 jsp 页面范围内有效
	request (HttpServletRequest 类)		一次请求内有效
	session (HttpSession 类)			一个会话范围内有效(打开浏览器访问服务器,直到关闭浏览器)
	application (ServletContext 类) 	整个 web 工程范围内都有效(只要 web 工程不停止,数据都在)

域对象是可以像 Map 一样存取数据的对象。

四个域对象功能一样。不同的是它们对数据的存取范围。

虽然四个域对象都可以存取数据。在使用上它们是有优先顺序的。

四个域在使用的时候,优先顺序分别是,他们从小到大的范围的顺序。
	pageContext ====>>> request ====>>> session ====>>> application

在这里插入图片描述

007-jsp 中的 out 输出和 response.getWriter 输出的区别

response 中表示响应,我们经常用于设置返回给客户端的内容(输出)
out 也是给用户做输出使用的。

out类的方法不能使用是因为缺少 jsp-api.jar
在这里插入图片描述

使用out还是response?
	由于 jsp 翻译之后,底层源代码都是使用 out 来进行输出
	所以一般情况下,我们在 jsp 页面中统一使用 out 来进行输出。避免打乱页面输出内容的顺序。

out有两种输出方法:
	out.write() 只能输出字符串
	out.print() 输出任意数据都没有问题(都转换成为字符串后调用的 out.write() 输出)

深入源码,浅出结论:在 jsp 页面中,可以统一使用 out.print()来进行输出

008-jsp 的常用标签

什么叫静态包含?
比如有10000个页面,但是每个页面中都会在页面底部写上相同的内容如友情链接等
如果要修改这些内容,一个一个改很麻烦,所以可以使用包含,可以同时改

在这里插入图片描述
在这里插入图片描述

(1)jsp 静态包含

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>main.jsp</title>
</head>
<body>
  头部信息 <br>
  主体内容 <br>
  
  <%--  
    <%@ include file=""%> 就是静态包含
    file 属性指定你要包含的 jsp 页面的路径
    地址中第一个斜杠 / 表示为 http://ip:port/工程路径/ 映射到IDEA的 web 目录
  --%>
  <%@ include file="/静态包含/footer.jsp"%>
  
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>footer.jsp</title>
</head>
<body>
  脚部信息
</body>
</html>
静态包含的特点:
1、静态包含不会翻译 被包含的 jsp 页面。
2、静态包含其实是把 被包含的 jsp 页面的代码 拷贝到包含的位置执行输出。

(2)jsp 动态包含

动态包含也可以实现静态包含的功能,只不过底层原理不同。

在这里插入图片描述

动态包含还可以传递参数,参数被传递到被包含的jsp页面,即footer.jsp页面

在这里插入图片描述
基本上使用静态包含

(3)jsp 标签-转发

在这里插入图片描述

009-jsp 的练习

(1)在 jsp 页面中输出九九乘法口诀
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
	<style type="text/css">
	table{
    
    
	width: 650px;
	}
	</style>
</head>
<body>
	<%-- 练习一:在 jsp 页面中输出九九乘法口诀表 --%>
	<h1 align="center">九九乘法口诀表</h1>
	<table align="center">
	<%-- 外层循环遍历行 --%>
	<% for (int i = 1; i <= 9; i++) {
    
     %>
	<tr>
	<%-- 内层循环遍历单元格 --%>
	<% for (int j = 1; j <= i ; j++) {
    
     %>
	<td><%=j + "x" + i + "=" + (i*j)%></td>
	<% } %>
	</tr>
	<% } %>
	</table>
</body>
</html>

(2)jsp 输出一个表格,里面有 10 个学生信息(使用请求转发)

在这里插入图片描述

SearchStudentServlet程序查询到学生信息之后,本可以直接传给客户端,
但是Servlet程序对于回传信息给客户端效率很低,所以将这个工作交给jsp做,所有请求转发

注意:访问时必须先访问SearchStudentServlet程序,再访问jsp

在这里插入图片描述

SearchStudentServlet 程序:
public class SearchStudentServlet extends HttpServlet {
    
    
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
    
    
	// 获取请求的参数
	// 发 sql 语句查询学生的信息
	// 使用 for 循环生成查询到的数据做模拟
	List<Student> studentList = new ArrayList<Student>();
	
	for (int i = 0; i < 10; i++) {
    
    
		int t = i + 1;
		studentList.add(new Student(t,"name"+t, 18+t,"phone"+t));
	}
	
	// 保存查询到的结果(学生信息)到 request 域中
	req.setAttribute("stuList", studentList);
	
	// 请求转发到 showStudent.jsp 页
	req.getRequestDispatcher("/test/showStudent.jsp").forward(req,resp);
	}
}

在这里插入图片描述

010-什么是 Listener 监听器?

1、Listener 监听器它是 JavaWeb 的三大组件之一。
	JavaWeb 的三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。
2、Listener 它是 JavaEE 的规范,就是接口
3、监听器的作用是,监听某种事物的变化。然后通过回调函数,反馈给客户(程序)去做一些相应的处理。

ServletContextListener 监听器

随着时代的发展,大多数监听器都没用了,只有ServletContextListener 监听器还有一些用。

ServletContextListener 它可以监听 ServletContext 对象的创建和销毁。

ServletContext 对象在 web 工程启动的时候创建,在 web 工程停止的时候销毁。

监听到创建和销毁之后都会分别调用 ServletContextListener 监听器的方法反馈。

两个方法分别是:

在这里插入图片描述

如何使用 ServletContextListener 监听器监听 ServletContext 对象。
	使用步骤如下:
		1、编写一个类去实现 ServletContextListener
		2、实现其两个回调方法
		3、到 web.xml 中去配置监听


监听器实现类:
public class MyServletContextListenerImpl implements ServletContextListener {
    
    
	@Override
	public void contextInitialized(ServletContextEvent sce) {
    
    
		System.out.println("ServletContext 对象被创建了");
	}
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
    
    
		System.out.println("ServletContext 对象被销毁了");
	}
}
web.xml 中的配置:
<!--配置监听器-->
<listener>
<listener-class>com.atguigu.listener.MyServletContextListenerImpl</listener-class>
</listener>

十一、EL表达式

001-什么是 EL 表达式,EL 表达式的作用?

EL 表达式的全称是:Expression Language。是表达式语言。
EL 表达式的什么作用:EL 表达式主要是代替 jsp 页面中的表达式脚本在 jsp 页面中进行数据的输出。

因为 EL 表达式在输出数据的时候,要比 jsp 的表达式脚本要简洁很多。

EL替换 <%= %>
在这里插入图片描述

EL 表达式的格式是:${表达式}

EL 表达式在输出 null 值的时候,输出的是空串。jsp 表达式脚本输出 null 值的时候,输出的是 null

002-EL 表达式搜索域数据的顺序

EL 表达式主要是在 jsp 页面中输出数据。

主要是输出域对象中的数据。

当四个域中都有相同的 key 的数据的时候,EL 表达式会按照四个域的从小到大的顺序去进行搜索,找到就输出。

在这里插入图片描述

003-EL 表达式输出 Bean 的普通属性,数组属性;List 集合属性,Map 集合属性

EL只能从四大域中获取值
要把person加到四大域中的某一个里
package classExample;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Person {
    
    
  // i.需求——输出 Person 类中普通属性,数组属性。list 集合属性和 map 集合属性。
  private String name;
  private String[] phones;
  private List<String> cities;
  private Map<String,Object> map;

  public Person() {
    
    
  }

  public Person(String name, String[] phones, List<String> cities, Map<String, Object> map) {
    
    
    this.name = name;
    this.phones = phones;
    this.cities = cities;
    this.map = map;
  }

  public String getName() {
    
    
    return name;
  }

  public void setName(String name) {
    
    
    this.name = name;
  }

  public String[] getPhones() {
    
    
    return phones;
  }

  public void setPhones(String[] phones) {
    
    
    this.phones = phones;
  }

  public List<String> getCities() {
    
    
    return cities;
  }

  public void setCities(List<String> cities) {
    
    
    this.cities = cities;
  }

  public Map<String, Object> getMap() {
    
    
    return map;
  }

  public void setMap(Map<String, Object> map) {
    
    
    this.map = map;
  }

  @Override
  public String toString() {
    
    
    return "Person{" +
      "name='" + name + '\'' +
      ", phones=" + Arrays.toString(phones) +
      ", cities=" + cities +
      ", map=" + map +
      '}';
  }
}

注意:
	EL表达式在这里其实调用了Person类中的get方法,如果没有get方法是无法使用EL的

注意要导包:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ page import="classExample.Person" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>

<html>
<head>
  <title>Title</title>
</head>
<body>
  <%
    Person person = new Person();
    person.setName("国哥好帅!");
    person.setPhones(new String[]{"18610541354","18688886666","18699998888"});

    List<String> cities = new ArrayList<String>();
    cities.add("北京");
    cities.add("上海");
    cities.add("深圳");
    person.setCities(cities);

    Map<String,Object> map = new HashMap<>();
    map.put("key1","value1");
    map.put("key2","value2");
    map.put("key3","value3");
    person.setMap(map);

    pageContext.setAttribute("p",person);//加到四大域中的一个
  %>

  输出 Person:${ p }
  <br>
  输出 Person 的 name 属性:${p.name}
  <br>
  输出 Person 的 phones 数组属性值:${p.phones[2]}
  <br>
  输出 Person 的 cities 集合中的元素值:${p.cities}
  <br>
  输出 Person 的 List 集合中个别元素值:${p.cities[2]}
  <br>
  输出 Person 的 Map 集合: ${p.map}
  <br>
  输出 Person 的 Map 集合中某个 key 的值: ${p.map.key3}

</body>
</html>


这里会出现一个问题:
在JSP中实例化类对象报编译错误“Classes from the default package must not be referenced from JSP file“

默认包下的Java类无法被JSP文件所引用,因此可以在src下新建一个包,将报错的Java类添加进该包当中,之后使用 <%@ page import="包名.类名" %> 进行导包。

在这里插入图片描述
在这里插入图片描述

004-运算

(1)关系运算

在这里插入图片描述

(2)逻辑运算

在这里插入图片描述

(3)算数运算

在这里插入图片描述

(4)empty运算

在这里插入图片描述
在这里插入图片描述

(5)三目运算

表达式 1?表达式 2:表达式 3

如果表达式 1 的值为真,返回表达式 2 的值,如果表达式 1 的值为假,返回表达式 3 的值

在这里插入图片描述

(6)“.” 点运算 和 [] 中括号运算符

.点运算,可以输出 Bean 对象中某个属性的值。

[]中括号运算,可以输出有序集合中某个元素的值。

并且[]中括号运算,还可以输出 map 集合中 key 里含有特殊字符的 key 的值。

在这里插入图片描述
在这里插入图片描述

005-EL 表达式的 11 个隐含对象

EL 个达式中 11 个隐含对象,是 EL 表达式中自己定义的,可以直接使用。
	变量 				类型 						作用
pageContext 		PageContextImpl 		它可以获取 jsp 中的九大内置对象
pageScope 			Map<String,Object> 		它可以获取 pageContext 域中的数据
requestScope 		Map<String,Object> 		它可以获取 Request 域中的数据
sessionScope 		Map<String,Object> 		它可以获取 Session 域中的数据
applicationScope 	Map<String,Object> 		它可以获取 ServletContext 域中的数据
param 				Map<String,String> 		它可以获取请求参数的值
paramValues 		Map<String,String[]> 	它也可以获取请求参数的值,获取多个值的时候使用。
header 				Map<String,String> 		它可以获取请求头的信息
headerValues 		Map<String,String[]> 	它可以获取请求头的信息,它可以获取多个值的情况
cookie 				Map<String,Cookie> 		它可以获取当前请求的 Cookie 信息
initParam 			Map<String,String> 		它可以获取在 web.xml 中配置的<context-param>上下文参数

(1)EL 获取四个特定域中的属性

pageScope 			====== 		pageContext 域
requestScope 		====== 		Request 域
sessionScope 		====== 		Session 域
applicationScope 	====== 		ServletContext 域

在这里插入图片描述
在这里插入图片描述

为什么有这个隐含对象?
	因为:
		request.setAttribute("key2","request");
		session.setAttribute("key2","session");
	如果:${key2} 不知道是哪一个key2
	所有有了隐含对象:
		${requestScope.key2}
		${sessionScope.key2}

(2)pageContext 对象的使用

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

(3)EL表达式其他隐含对象的使用

在这里插入图片描述

请求地址:
http://localhost:8080/09_EL_JSTL/other_el_obj.jsp?username=wzg168&password=666666&hobby=java&hobby=cpp

输出请求参数 username 的值:${ param.username } 
输出请求参数 password 的值:${ param.password } 

输出请求参数 hobby 的值:${ paramValues.hobby[0] } 
输出请求参数 hobby 的值:${ paramValues.hobby[1] } 

在这里插入图片描述

输出请求头【User-Agent】的值:
	//${ header.User-Agent } 这样写是不行的
	正确写法:${ header['User-Agent'] }  

输出请求头【Connection】的值:${ header.Connection } 
输出请求头【User-Agent】的值:${ headerValues['User-Agent'][0] } 

在这里插入图片描述

${cookie}
结果:

在这里插入图片描述


在这里插入图片描述

jdbc:mysql:///test   --->即   jdbc:mysql://localhost:3306/test

输出<Context-param> username 的值:${ initParam.username } <br>
输出<Context-param> url 的值:${ initParam.url } <br>

${initParam} 结果是:

在这里插入图片描述

十二、JSTL标签库

001-介绍

JSTL 替换 <% %>

JSTL 标签库 全称是指 JSP Standard Tag Library JSP 标准标签库。是一个不断完善的开放源代码的 JSP 标签库。

EL 表达式主要是为了替换 jsp 中的表达式脚本,而标签库则是为了替换代码脚本。这样使得整个 jsp 页面变得更佳简洁。

在这里插入图片描述

在 jsp 标签库中使用 taglib 指令引入标签库

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

XML 标签库
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>

FMT 标签库
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

SQL 标签库
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>

FUNCTIONS 标签库
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %

002-JSTL 标签库的使用步骤

在这里插入图片描述

可以导入上面两个jar包,
也可以导入下面4个最新版的jar包。

但是必须在WEB-INF目录下创建一个lib目录,然后把jar包放到lib里面,然后右击lib选择add as library,其他方法不行。

得使用tomcat8.5,tomcat10不兼容。

在这里插入图片描述

003-core 核心库使用

(1)set标签

<c:set></c:set>(使用很少)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

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

<html>
<head>
  <title>Title</title>
</head>
<body>
  <%--
    <c:set></c:set>
      作用:set 标签可以往域中保存数据

    如何往域中保存数据?
      格式:域对象.setAttribute(key,value);
      1.保存到那个域
      2.key是多少
      3.value是多少
    
    set标签:
      scope 属性设置保存到哪个域
        page 表示 PageContext 域(默认值)
        request 表示 Request 域
        session 表示 Session 域
        application 表示 ServletContext 域
      var 属性设置 key 是多少
      value 属性设置值
  --%>

  保存之前:${ sessionScope.abc } <br> <%--为空--%>

  <c:set scope="session" var="abc" value="abcValue"/>

  保存之后:${ sessionScope.abc } <br>

</body>
</html>

(2)if标签

<c:if ></c:if>

在这里插入图片描述

(3)choose、when、otherwise标签

<c:choose></c:choose>
<c:when></c:when>
<c:otherwise></c:otherwise>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
  <title>Title</title>
</head>
<body>

  <%--
    作用:多路判断。跟 switch ... case .... default 非常接近

    choose 标签开始选择判断
    when 标签表示每一种判断情况
      test 属性表示当前这种判断情况的值(使用EL表达式)
    otherwise 标签表示剩下的情况

    需要注意的点:
      1、标签里不能使用 html 注释,要使用 jsp 注释
      2、when 标签的父标签一定要是 choose 标签
  --%>

  <%
    request.setAttribute("height", 180);
  %>

  <c:choose>
    <%-- 这是 jsp 注释 --%>
    <c:when test="${ requestScope.height > 190 }">
      <h2>小巨人</h2>
    </c:when>
    <c:when test="${ requestScope.height > 180 }">
      <h2>很高</h2>
    </c:when>
    <c:when test="${ requestScope.height > 170 }">
      <h2>还可以</h2>
    </c:when>
    <c:otherwise>
      <%--这里要先写choose--%>
      <c:choose>
        <c:when test="${requestScope.height > 160}">
          <h3>大于 160</h3>
        </c:when>
        <c:when test="${requestScope.height > 150}">
          <h3>大于 150</h3>
        </c:when>
        <c:when test="${requestScope.height > 140}">
          <h3>大于 140</h3>
        </c:when>
        <c:otherwise>
          其他小于 140
        </c:otherwise>
      </c:choose>
    </c:otherwise>
  </c:choose>

</body>
</html>

(4)foreach标签

<c:forEach></c:forEach>

作用:遍历输出使用。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
  <title>Title</title>
</head>
<body>

  <%--
    1.遍历 1 到 10,输出
      begin 属性设置开始的索引
      end 属性设置结束的索引
      var 属性表示循环的变量(也是当前正在遍历到的数据)
      for (int i = 1; i < 10; i++)
  --%>
  <table border="1">
    <c:forEach begin="1" end="10" var="i">
      <tr>
        <td>第${i}行</td>
      </tr>
    </c:forEach>
  </table>

</body>
</html>
<%-- 
	2.遍历 Object 数组
	for (Object item: arr)
		items 表示遍历的数据源(遍历的集合)
		var 表示当前遍历到的数据
	--%>

<%
	request.setAttribute("arr", new String[]{"18610541354","18688886666","18699998888"});
%>

<c:forEach items="${ requestScope.arr }" var="item">
	${ item } <br>
</c:forEach>
3.遍历Map集合

<%
	Map<String,Object> map = new HashMap<String, Object>();
	map.put("key1", "value1");
	map.put("key2", "value2");
	map.put("key3", "value3");
	
	// for ( Map.Entry<String,Object> entry : map.entrySet()) {}
	
	request.setAttribute("map", map);
%>
<c:forEach items="${ requestScope.map }" var="entry">
	<h1>${entry}</h1>//输出键值对
	//只输出key:${entry.key}
	//只输出value:${entry.value}
</c:forEach>

package classExample;

public class Student {
    
    
  //4.编号,用户名,密码,年龄,电话信息
  private Integer id;
  private String username;
  private String password;
  private Integer age;
  private String phone;

  public Student() {
    
    
  }

  public Student(Integer id, String username, String password, Integer age, String phone) {
    
    
    this.id = id;
    this.username = username;
    this.password = password;
    this.age = age;
    this.phone = phone;
  }

  public Integer getId() {
    
    
    return id;
  }

  public void setId(Integer id) {
    
    
    this.id = id;
  }

  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 Integer getAge() {
    
    
    return age;
  }

  public void setAge(Integer age) {
    
    
    this.age = age;
  }

  public String getPhone() {
    
    
    return phone;
  }

  public void setPhone(String phone) {
    
    
    this.phone = phone;
  }

  @Override
  public String toString() {
    
    
    return "Student{" +
      "id=" + id +
      ", username='" + username + '\'' +
      ", password='" + password + '\'' +
      ", age=" + age +
      ", phone='" + phone + '\'' +
      '}';
  }
}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="classExample.Student" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
  <title>Title</title>
</head>
<body>

  <%--4.遍历 List 集合---list 中存放 Student 类,有属性:编号,用户名,密码,年龄,电话信息--%>
  <%
    List<Student> studentList = new ArrayList<Student>();
    for (int i = 1; i <= 10; i++) {
      studentList.add(new Student(i,"username"+i ,"pass"+i,18+i,"phone"+i));
    }
    request.setAttribute("stus", studentList);
  %>

  <table>
    <tr>
      <th>编号</th>
      <th>用户名</th>
      <th>密码</th>
      <th>年龄</th>
      <th>电话</th>
      <th>操作</th>
    </tr>

    <c:forEach items="${requestScope.stus}" var="stu">
      <tr>
        <td>${stu.id}</td>
        <td>${stu.username}</td>
        <td>${stu.password}</td>
        <td>${stu.age}</td>
        <td>${stu.phone}</td>
        <td>删除...</td>
      </tr>
    </c:forEach>
  </table>

</body>
</html>

在这里插入图片描述

varStatus表示当前遍历到的数据的状态
varStatus="这里可以随便写"

${status} 可以得到:

在这里插入图片描述

这是一个Status内部类
在javax.servlet.jsp.jstl.core.LoopTagSupport下找到Status
Status类实现了LoopTagSupport接口

在这里插入图片描述

${status.current}
${status.index}
${status.count}
${status.first}
${status.last}
${status.begin}
${status.end}
${status.step}

十三、文件的上传和下载

在这里插入图片描述

001-文件的上传

(1)操作步骤

在这里插入图片描述

如何创建Servlet程序:

创建servlet程序:
	1.创建java文件 + 在web-xml中手动配置访问地址
	2.创建servlet文件 + 使用annotation注解(需要annotations-api.jar) 更简单的配置地址
		需要servlet-api.jar包
		需要 Settings-->Modules--->选中模块--->web--->选择source roots
		然后创建servlet文件时选择 create java EE 6+ annotated class

上面两个jar包在 tomcat文件夹的lib文件夹里都有

创建一个表单,上传图片:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2)文件上传-HTTP说明

为什么文件上传要使用 post 请求?
	因为 get 请求是有长度限制的,post 请求可以超出长度限制。

在这里插入图片描述
在这里插入图片描述

(3)解析服务器收到的数据

在浏览器填写一个表单,这个表单中有普通的表单项(如填写name),也有上传的文件。
点击提交按钮之后,浏览器会将数据提交给服务器,服务器会接收数据,
如果要进一步对接收到的数据进行处理,可以使用别人已经封装好的方法:下面的两个jar包

服务器接收到的数据两种:
	普通的表单项(如填写姓名的文本框)和 上传的文件。
	要分开进行处理。

在这里插入图片描述
在这里插入图片描述

注意:tomcat10 用 jakarta 替换了 前面版本的 javax
但是 ServletFileUpload.isMultipartContent( javax.servlet.http.HttpServletRequest request)
这个方法需要的参数的request 是 javax 中的 request
所以不能使用 tomcat 10 中的lib 的jar 包, 要使用 tomcat 8 的lib 的jar包

也不能使用注解创建Servlet程序了,因为注解是jakarta下的;
只能创建java文件,手动配置web-xml。

files--->project structure--->modules--->选择模块--->点右边的 + 好--->选tomcat 8

重点在于需要:javax包!
package com.atguigu.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class UploadServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //服务器如何处理 从浏览器发来的数据(包括如何处理上传的文件)?
        //别人已经封装好了方法:导入common-fileupload.jar 和要依赖的 common-io.jar

        //1.判断当前上传的数据格式是否是多段的格式(只有多段的格式才是提交的数据)
        if(ServletFileUpload.isMultipartContent(request)){
    
    
            //创建FileItemFactory实现类(因为FileItemFactory是一个接口)
            FileItemFactory fileItemFactory = new DiskFileItemFactory();

            //创建用于解析上传数据的工具类
            ServletFileUpload servletFile = new ServletFileUpload(fileItemFactory);

            try {
    
    
                //解析上传的数据,得到每一个表单项
                List<FileItem> fileItems = servletFile.parseRequest(request);

                //循环判断每一个表单项,是一个普通表单项,还是一个文件
                for (FileItem fileItem:fileItems) {
    
    
                    if(fileItem.isFormField()){
    
    
                        //普通的表单项

                        System.out.println("表单项的name属性值:" + fileItem.getFieldName());
                        //UTF-8解决乱码问题
                        System.out.println("表单项的value属性值:" + fileItem.getString("UTF-8"));
                    }else{
    
    
                        //上传的文件

                        System.out.println("表单项的name属性值:" + fileItem.getFieldName());
                        //UTF-8解决乱码问题
                        System.out.println("上传的文件名:" + fileItem.getName());

                        //将上传的文件写到 参数 file 所指向的硬盘位置
                        fileItem.write(new File("D://" + fileItem.getName()));
                    }
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述
在这里插入图片描述

002-文件的下载

在这里插入图片描述

package com.atguigu.servlet;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

public class DownloadServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //1.获取要下载的文件名
        String downloadFilename = "start.jpg";

        //2.读取要下载的文件(通过ServletContext对象可以读取)
        ServletContext servletContext = getServletContext();

        //4.在回传前,通过响应头告诉客户端回传的文件的类型
        //获取要下载的文件的类型
        String mineType = servletContext.getMimeType("/files/" + downloadFilename);

        //回传给客户端要下载的文件的类型
        resp.setContentType(mineType);

        //5.还要告诉客户端,从服务器收到的数据要下载才能使用(通过响应头)
        //Content-Disposition响应头:表示收到的数据如何处理
        //attachment 表示附件,表示下载使用
        //filename= 表示指定下载的文件名(filename=可以任意取名,不用一定=downloadFilename)
        //resp.setHeader("Content-Disposition", "attachment; filename=" + downloadFilename);
        //filename=中文,会乱码,要改为下面这种
        resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中国.jpg" + "UTF-8"));


        //在web目录下创建一个目录files,存放要下载的文件
        // 第一个/斜杠被服务器解析表示地址为http://ip:port/工程名/
        //映射到IDEA中的web目录
        InputStream resourceAsStream = servletContext.getResourceAsStream("/files/" + downloadFilename);

        //获取响应的输出流
        OutputStream outputStream = resp.getOutputStream();

        //3.把下载的文件回传给客户端
        //读取输入流中全部的数据,复制给输出流,输出给客户端
        IOUtils.copy(resourceAsStream,outputStream);
    }
}

在这里插入图片描述

注意:
filename= 表示指定下载的文件名(filename=可以任意取名,不用一定=downloadFilename)
不过如果filename=中文,会出现乱码,要这样写:
	resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中国.jpg", "UTF-8"));

上述方法 谷歌浏览器 和 IE浏览器都可以使用。
但是火狐浏览器不支持这种做法。(现在新版火狐也支持上述做法了,下面就了解一下)

火狐浏览器是Base64编码。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_52041525/article/details/123517462