DW-CHEN的Java点滴记录JavaWeb之HTTP协议ServletCookieSessionJSPELJSTLFilterListener

tech2022-10-28  69

JavaEE规范

JavaEE(Java Enterprise Edition):Java企业版,早期叫J2EE(J2EE的版本从1.0到1.4结束);现在Java版本从JavaEE 5开始

JavaEE规范是很多Java开发技术的总称

HTTP协议

HTTP(Hyper Text Transfer Protocol):超文本传输协议 HTTP协议是基于TCP/IP协议的 超文本:比普通文本更加强大 传输协议:客户端和服务端的通信规则(握手规则)

HTTP协议的请求

请求的组成规则

请求行请求头请求空行请求体
请求方式
GETPOST 注意:只有POST请求方式才有请求体
请求行
请求方式提交路径(提交参数)HTTP/版本号
请求头
名称说明Accept客户端浏览器所支持的MIME类型Accept-Encoding客户端浏览器所支持的压缩编码格式,最常用的就是gzip压缩Accept-Language客户端浏览器所支持的语言,一般都是zh_CN或en_US等Referer告知服务器当前请求来源Content-Type请求正文所支持MIME类型Content-Length请求正文的长度User-Agent浏览器相关信息Connection连接状态,Keep-Alive保持连接If-Modified-Since客户端浏览器缓存文件的最后修改时间Cookie会话管理相关
请求空行
普通换行,用于区分请求头和请求体
请求体
只有POST提交方式才有请求体,用于显示提交数据

HTT协议的响应

响应的组成部分

响应行响应头响应空行响应体
响应行
请求方式HTTP/版本号 状态码 状态描述常见状态码 状态码说明200一切ok302/307请求重定向,两次请求,地址栏发生改变304请求资源未发生改变,使用缓存404请求资源未找到500服务器错误
响应头
名称说明Location请求重定向地址,常与302,307配合使用Server服务器相关信息Content-Type响应正文的MIME类型Content-Length响应正文的长度Content-Disposition告知客户端浏览器,以下载的方式打开响应正文Refresh定时刷新Last-Modified服务器资源的最后修改时间Set-Cookie会话管理相关Expires:-1服务器资源到客户端浏览器后的缓存数据Catch-Control:no-catch不要缓存
响应空行
普通换行,用于区分响应头和响应体
响应体
将资源文件发送给客户端浏览器进行解析

Servlet

Servlet是运行在Java服务器端的程序,用户接收和响应客户端基于HTTP协议的请求如果想实现Servlet功能,可以通过实现javax.servlet.Servlet接口或者继承它的实现类核心方法:service(),任何客户端的请求都会经过该方法

动态web项目创建 idea配置tomcat服务器

Servlet实现方式

servlet配置

配置默认访问页面 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>/demo/index.jsp</welcome-file> </welcome-file-list> </web-app> web.xml配置文件配置,在web/WEB-INF/web.xml配置文件中进行配置Servlet映射 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>/demo/index.jsp</welcome-file> </welcome-file-list> <!--配置Servlet--> <servlet> <servlet-name>servletName</servlet-name> <servlet-class>cn.cdw.demo.Demo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>servletName</servlet-name> <url-pattern>/servletDemo</url-pattern> </servlet-mapping> </web-app> 注解的方式配置,在Servlet类上添加注解进行配置 @WebServlet("访问映射路径")

实现Servlet接口

实现Servlet接口,实时所有的抽象方法,该方式支持最大程度的自定义servlet-api.jar包下载:https://download.csdn.net/download/qq_42795277/12804264 package cn.cdw.demo; import javax.servlet.*; import java.io.IOException; /** * DW-CHEN * Servlet * * 如果实现Servlet接口报cannot resolve symbol 'servlet'异常,那么需要手动都如servlet-api.jar包 */ public class Demo1 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("service方法执行了,测试通过...."); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }

继承GenericServlet抽象类

继承GenericServlet抽象类,必须重写service方法,其他的方法可以选择重写,该方式让我们开发Servlet变得简单,但是这个方式和HTTP协议无关 package cn.cdw.demo; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import java.io.IOException; /** * @author DW-CHEN * GenericServlet */ @WebServlet("/servletDemo2") public class Demo2 extends GenericServlet { @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("继承GenericServlet实现类的重写service方法执行了,测试通过...."); } }

继承HttpServlet抽象类

继承HttpServlet抽象类,需要重写doGet和doPost方法,该方式表示请求和响应都需要和HTTP协议相关 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * HttpServlet */ @WebServlet("/servletDemo3") public class Demo3 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("测试通过...."); } }

Servlet生命周期

对象的生命周期,就是对象从出生到死亡的过程,官方的说法就是对象的创建到销毁的过程

出生:请求第一次到达Servlet时,对象就创建出来,并且初始化成功,只出生一次,将对象放到内存中

活着:服务提供服务的整个过程中,该对象一直存在,每次都是执行service方法

死亡:当服务停止时或者服务器宕机时,对象死亡

Servlet对象只会创建一次,销毁一次,所有Servlet对象只有一个实例,如果一个对象实例在应用中时唯一存在,我们可以称为单例模式

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * Servlet生命周期 */ @WebServlet("/servletDemo4") public class Demo4 extends HttpServlet { //初始化 @Override public void init() throws ServletException { System.out.println("初始化了...."); } //服务 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("服务过程....."); } //销毁 @Override public void destroy() { System.out.println("销毁了...."); } }

Servlet线程安全问题

由于Servlet采用的是单例模式,也就是整个应用中只有一个实例对象(Servlet是线程不安全的)

Servlet线程不安全问题展示

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * Servlet线程安全问题 * * 使用两个浏览器同时访问同一个请求,出现线程安全问题 * * 例如 * 浏览器一访问:http://localhost:8080/servletDemo5?testName=aaa * 浏览器二访问:http://localhost:8080/servletDemo5?testName=bbb * * 出现:浏览器1和浏览器2页面显示都是bbb * * */ @WebServlet("/servletDemo5") public class Demo5 extends HttpServlet { private String value;//定义接收请求值的属性 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { value = req.getParameter("testName");//获取请求testName属性的值 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } PrintWriter writer = resp.getWriter(); writer.write("value:" + value);//把请求参数值响应到页面 writer.close(); } } 解决:定义类成员要谨慎,如果是共用的,并且只会在初始化时赋值,其他时间都是获取的话,那么是没问题的,如果不是共用的,或者每次使用都有可能对其赋值,那么要考虑线程安全问题了,可以将其定义到doGet或doPost方法内或者使用同步功能即可

解决Servlet线程安全问题:把成员变量定义到局部变量

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * 解决Servlet线程安全问题:把成员变量定义到局部变量 */ @WebServlet("/servletDemo6") public class Demo6 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String value = null; value = req.getParameter("testName");//获取请求testName属性的值 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } PrintWriter writer = resp.getWriter(); writer.write("value:" + value);//把请求参数值响应到页面 writer.close(); } }

使用同步代码块解决Servlet线程安全问题

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * 使用同步代码块解决Servlet线程安全问题 */ @WebServlet("/servletDemo7") public class Demo7 extends HttpServlet { private String value; private Object lock = new Object(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { synchronized (lock) { value = req.getParameter("testName");//获取请求testName属性的值 } try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } PrintWriter writer = resp.getWriter(); writer.write("value:" + value);//把请求参数值响应到页面 writer.close(); } }

Servlet映射方式

具体名称的方式,访问的资源路径必须和映射配置完全相同/ 开头 + 通配符的方式,只要符合目录结构即可,不用考虑结尾是什么通配符 + 固定格式结尾的方式,只有符合固定结尾格式即可,不用考虑前面的路径

注意:优先级问题,越是具体的优先级越高,也是模糊通用的优先级越低

通过多映射配置,在不同的访问路径在同一个方法里实现不同的功能逻辑

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * 通过多映射配置,在不同的访问路径在同一个方法里实现不同的功能逻辑 * * 例如:访问路径结尾为vip的购物优惠八折,为svip的购物优惠五折,普通不优惠 */ @WebServlet("/servletDemo8/*") public class Demo8 extends HttpServlet { private Integer money = 10000; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { StringBuffer requestURL = req.getRequestURL(); String url = requestURL.substring(requestURL.lastIndexOf("/"));//获取最后一个路径字符串 PrintWriter writer = resp.getWriter(); if ("/vip".equals(url)) { System.out.println("价钱:"+money + " 优惠后八折后为:"+(money) * 0.8); writer.write(String.valueOf((money) * 0.8)); }else if ("/svip".equals(url)) { System.out.println("价钱:"+money + " 优惠后八折后为:"+(money) * 0.5); writer.write(String.valueOf((money) * 0.5)); }else { System.out.println("价钱:" + money + " 没有优惠"); writer.write(String.valueOf((money))); } } }

Servlet创建时机

第一次访问的时候创建

优势:减少对服务器内存的浪费,提高服务器启动的效率弊端:如果有一些需要应用加载时就做的初始化操作,无法完成

服务器加载时启动

优势:提前创建好对象,提高了首次执行的效率,可以完成一些应用加载要做的初始化操作弊端:对服务器内存占用较多,影响了服务器启动的效率配置:修改web.xml,在<servlet>标签中,添加<load-on-startup>1</load-on-startup>(web.xml配置的方式),说明:正数表示服务器加载时创建,值越小,优先级越高,负数或不写代表第一次访问创建

注解配置的方式

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; /** * @author DW-CHEN * * 配置Servlet在服务器启动的时候就创建初始化 */ @WebServlet(value = "/servletDemo9",loadOnStartup = 1) public class Demo9 extends HttpServlet { @Override public void init() throws ServletException { System.out.println("Servlet初始化了..."); } }

web.xml配置

默认Servlet

默认Servlet是由服务器提供的一个Servlet,它配置在Tomcat8的conf目录的web.xml中

它的配置路径是<url-pattern>/</url-pattern>,我们发送请求时,首先会在我们项目中的web.xml中查找映射配置,找到则执行,但是当找不到对应的Servlet路径时,就去找默认的Servlet,由默认Servlet处理,所以,一切都是Servlet

ServletConfig

ServletConfig是Servlet的配置参数对象,在Servelt的规范中,允许为每一个Servlet都提供一些初始化的配置,所以每一个Servlet都有一个自己的ServletConfig作用:在Servlet的初始化时,把一些配置信息传递给Servlet生命周期:和Servelt一样

ServletConfig配置方式

在<servlet>标签中,通过<init-param>标签来配置,有两个子标签<param-name>:代表初始化参数的key<param-value>:代表初始化参数的value <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>/demo/index.jsp</welcome-file> </welcome-file-list> <!--Demo10--> <servlet> <servlet-name>servletName10</servlet-name> <servlet-class>cn.cdw.demo.Demo10</servlet-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>desc</param-name> <param-value>this is ServletConfig</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>servletName10</servlet-name> <url-pattern>/servletDemo10</url-pattern> </servlet-mapping> </web-app>

ServletConfig常用方法

方法名说明String getInitParameter(String var1)根据参数名获取参数值Enumeration<String> getInitParameterNames()获取所有参数名称的枚举String getServletName()获取Servlet的名称ServletContext getServletContext()获取ServletContext对象 package cn.cdw.demo; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; /** * @author DW-CHEN * ServletConfig常用的方法 */ public class Demo10 extends HttpServlet { private ServletConfig servletConfig; @Override public void init(ServletConfig config) throws ServletException { this.servletConfig = config;//在init方法对ServletConfig进行赋值 } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); System.out.println("=========================根据参数key获取到值============================"); String encoding = servletConfig.getInitParameter("encoding"); System.out.println(encoding); writer.write(encoding); System.out.println(); System.out.println("=========================获取Servlet初始化配置所有数据============================"); Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()) { String key = initParameterNames.nextElement(); System.out.println(key + " : "+ servletConfig.getInitParameter(key)); writer.write("\r\n"+key + " : " + servletConfig.getInitParameter(key)); } System.out.println(); System.out.println("=========================获取配置的Servlet名============================"); String servletName = servletConfig.getServletName(); System.out.println(servletName); writer.write("\r\n"+servletName); System.out.println(); System.out.println("=========================获取配置的ServletContext对象============================"); System.out.println(servletConfig.getServletContext()); writer.write("\r\n"+servletConfig.getServletContext().toString()); } }

ServletContext

ServletContext是应用上下文对象(应用域对象),每一个应用中只有一个ServletContext对象作用:可以配置和获得应用的全局初始化参数,可以实现Servlet之间的数据共享生命周期:应用一加载则创建,应用停止则销毁

域对象

域对象指的是对象有作用域,也就是作用的范围。域对象可以实现数据的共享,不同作用范围的域对象共享数据的能力也不一样在Servlet规范中,一共有4个域对象,ServletContext就是其中一个,它也是web应用中最大的作用域,也叫application域,它可以实现整个应用之间的数据共享

ServletContext配置方式

在<web-app>标签中,通过<context-param>标签来配置,有两个子标签<param-name>:代表全局初始化参数的key<param-value>:代表全局初始化参数的value <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>/demo/index.jsp</welcome-file> </welcome-file-list> <!--配置全局参数--> <context-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </context-param> <context-param> <param-name>globalDesc</param-name> <param-value>this is ServletContext</param-value> </context-param> </web-app>

ServletContext常用方法

方法名说明String getInitParameter(String var1)根据名称获取全局配置的参数String getContextPath()获取当前应用的访问虚拟目录String getRealPath(String var1)根据虚拟目录获取应用部署的磁盘绝对路径void setAttribute(String var1, Object var2)向应用域对象中存储数据Object getAttribute(String var1)通过名称获取应用域对象中的数据void removeAttribute(String var1)通过名称移除应用域对象中的数据 package cn.cdw.demo; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; /** * @author DW-CHEN * ServletContext */ @WebServlet("/servletDemo11") public class Demo11 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext();//获取ServletContext对象 PrintWriter writer = resp.getWriter(); System.out.println("=======================根据name获取ServletContext配置数据========================"); String globalEncoding = servletContext.getInitParameter("globalEncoding"); System.out.println(globalEncoding); writer.write(globalEncoding); writer.write("\r\n"); System.out.println(); System.out.println("=======================获取ServletContext所有配置数据========================"); Enumeration<String> initParameterNames = servletContext.getInitParameterNames(); while (initParameterNames.hasMoreElements()) { String s = initParameterNames.nextElement(); System.out.println(s + " : " + servletContext.getInitParameter(s)); writer.write(s + " : " + servletContext.getInitParameter(s)+"\r\n"); } System.out.println(); System.out.println("=======================获取当前应用访问的虚拟目录========================"); String contextPath = servletContext.getContextPath(); System.out.println(contextPath); writer.write(contextPath); writer.write("\r\n"); System.out.println(); System.out.println("=======================根据虚拟目录获取应用部署在磁盘的绝对路径========================"); String realPath = servletContext.getRealPath("/"); System.out.println(realPath); writer.write(realPath); writer.write("\r\n"); writer.close(); /* getRealPath(String var1)一般用于获取磁盘中文件的绝对路径 例如: 在src目录下创建a.txt web目录下创建b.txt WEB-INF目录下创建c.txt 然后获取到它们各个在应用部署目录的绝对路径 */ System.out.println(); System.out.println("==================================================="); System.out.println(servletContext.getRealPath("/web/classes/a.txt")); System.out.println(servletContext.getRealPath("/web/b.txt")); System.out.println(servletContext.getRealPath("/c.txt")); } }

ServletContext域对象设置共享数据

package cn.cdw.demo; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * ServletContext数据共享 */ @WebServlet("/servletDemo12") public class Demo12 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); servletContext.setAttribute("data", "this is data data.....");//共享数据 //servletContext.removeAttribute("data");//删除共享数据 } }

获取ServletContext域对象数据

package cn.cdw.demo; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * ServletContext数据共享 */ @WebServlet("/servletDemo13") public class Demo13 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = getServletContext(); String data = (String)servletContext.getAttribute("data");//获取共享数据 System.out.println(data); resp.getWriter().write(data); } }

手动创建servlet容器

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * 手动创建servlet容器 * * 注意:需要在src下创建META-INF包,然后在这个包下创建services包,然后在这个包下创建javax.servlet.ServletContainerInitializer文件,然后在这个文件里写注册配置servlet的类的全类名 */ public class Demo15 extends HttpServlet { @Override public void init() throws ServletException { System.out.println("手动创建容器初始化..."); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("手动创建容器测试通过..."); resp.getWriter().write("TEST SUCCESS...."); } }
注册配置Servlet的功能类
package cn.cdw.demo; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import java.util.Set; /** * @author DW-CHEN * 注册配置Servlet的功能类 */ public class MyRegister implements ServletContainerInitializer { @Override public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException { Demo15 demo15 = new Demo15(); ServletRegistration.Dynamic servletDynamic = servletContext.addServlet("servletDemo15", demo15);//在ServletContext对象中添加Servlet,得到Servlet动态配置对象 servletDynamic.addMapping("/servletDemo15");//设置映射访问资源路径 servletDynamic.setLoadOnStartup(1);//设置servlet加载时机,启动时加载 } }
在src下创建META-INF包,然后在这个包下创建services包,然后在这个包下创建javax.servlet.ServletContainerInitializer文件,然后在这个文件里写注册配置servlet的类的全类名
cn.cdw.demo.MyRegister

请求对象Rquest

请求对象常用的方法-获取各种路径

方法名说明String getContextPath()获取虚拟目录名称String getServletPath()获取Servlet映射路径String getRemoteAddr()获取访问者ip地址String getQueryString()获取请求的消息数据String getRequestURI()获取统一资源标识符StringBuffer getRequestURL()获取统一资源定位符 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * * request常用方法-获取各种路径 */ @WebServlet("/servletDemo17") public class Demo17 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); System.out.println("========================获取虚拟路径==========================="); String contextPath = req.getContextPath(); System.out.println(contextPath); writer.write(contextPath); writer.write("\r\n"); System.out.println(); System.out.println("========================获取请求映射路径==========================="); String servletPath = req.getServletPath(); System.out.println(servletPath); writer.write(servletPath); writer.write("\r\n"); System.out.println(); System.out.println("========================获取请求数据==========================="); String queryString = req.getQueryString(); System.out.println(queryString); writer.write(queryString); writer.write("\r\n"); System.out.println(); System.out.println("========================获取请求ip==========================="); String remoteAddr = req.getRemoteAddr(); System.out.println(remoteAddr); writer.write(remoteAddr); writer.write("\r\n"); System.out.println(); System.out.println("========================获取请求标识路径==========================="); String requestURI = req.getRequestURI(); System.out.println(requestURI); writer.write(requestURI); writer.write("\r\n"); writer.close(); System.out.println(); System.out.println("========================获取请求定位符路径==========================="); StringBuffer requestURL = req.getRequestURL(); System.out.println(requestURL); writer.write(new String(requestURL)); writer.write("\r\n"); writer.close(); } }

请求对象常用方法-获取请求头信息

方法名说明String getHeader(String name)根据请求头名称获取对应的值Enumeration<String> getHeaders(String name)根据请求头名称获取多个值Enumeration<String> getHeaderNames()获取所有请求头名称 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; /** * @author DW-CHEN * request常用获取请求头信息方法 */ @WebServlet("/servletDemo18") public class Demo18 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); System.out.println("==========================获取所有请求头信息============================="); Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()){ String name = headerNames.nextElement(); System.out.println("header: " + name + " values: " + req.getHeader(name)); writer.write("header: " + name + " values: " + req.getHeader(name)); writer.write("\r\n"); } System.out.println(); System.out.println("=====================根据请求头获取对应的请求信息的值=========================="); String connection = req.getHeader("connection"); System.out.println(connection); writer.write(connection); writer.write("\r\n"); System.out.println(); System.out.println("============================根据请求头获取它所有的请求信息的值======================================"); Enumeration<String> headerValues = req.getHeaders("accept-encoding"); while (headerValues.hasMoreElements()) { String value = headerValues.nextElement(); System.out.println(value); writer.write(value); writer.write("\r\n"); } writer.close(); } }

请求对象常用方法-获取请求参数信息

方法名说明String getParameter(String name)根据名称获取数据String[] getParameterValues(String name)根据名称获取所有的数据Enumeration<String> getParameterNames()获取所有的名称Map<String,String[]> getParameterMap()获取所有参数键值对

html测试页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> <style> .div1{ width: 1200px; height: 800px; border: solid 1px red; } .div2{ width: 600px; height: 50%; margin-left: 500px; margin-top: 20px; } </style> </head> <body> <div class="div1"> <div class="div2"> <form action="/request/servletDemo19" method="get" autocomplete="off"> 姓名:<input type="text" name="name"><br/><br/> 密码:<input type="password" name="password"><br/><br/> 喜好:<input type="checkbox" name="hobby" value="play">玩游戏 <input type="checkbox" name="hobby" value="sleep">睡觉<br/><br/> <button type="submit">注册</button> </form> </div> </div> </body> </html>

Java代码

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; import java.util.Enumeration; import java.util.Map; import java.util.Set; /** * @author DW-CHEN * request获取请求参数常用方法 * 注意:这里并未处理中文乱码问题 */ @WebServlet("/servletDemo19") public class Demo19 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); System.out.println("======================获取请求参数属性获取请求参数数据======================="); String name = req.getParameter("name"); System.out.println(name); writer.write(name+"\r\n"); System.out.println(); System.out.println("===================根据请求属性名获取它对应的所有值====================="); String[] hobbies = req.getParameterValues("hobby"); System.out.println(Arrays.toString(hobbies)); writer.write(Arrays.toString(hobbies)+"\r\n"); System.out.println(); System.out.println("=======================获取所有请求参数数据======================================"); Enumeration<String> parameterNames = req.getParameterNames(); while (parameterNames.hasMoreElements()){ String getName = parameterNames.nextElement(); System.out.println(getName + " : " + Arrays.toString(req.getParameterValues(getName))); writer.write(getName + " : " + Arrays.toString(req.getParameterValues(getName))+"\r\n"); } System.out.println(); System.out.println("===================获取所有的请求参数数据以键值对方式======================="); Map<String, String[]> parameterMap = req.getParameterMap(); Set<String> keySet = parameterMap.keySet(); for (String key : keySet) { System.out.println(key + " :" + Arrays.toString(req.getParameterValues(key))); writer.write(key + " :" + Arrays.toString(req.getParameterValues(key))+"\r\n"); } writer.close(); } }

获取请求参数并封装到对象

手动封装的方式

html测试页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> <style> .div1{ width: 1200px; height: 800px; border: solid 1px red; } .div2{ width: 600px; height: 50%; margin-left: 500px; margin-top: 20px; } </style> </head> <body> <div class="div1"> <div class="div2"> <form action="/request/servletDemo20" method="get" autocomplete="off"> 姓名:<input type="text" name="name"><br/><br/> 密码:<input type="password" name="password"><br/><br/> 喜好:<input type="checkbox" name="hobby" value="play">玩游戏 <input type="checkbox" name="hobby" value="sleep">睡觉<br/><br/> <button type="submit">注册</button> </form> </div> </div> </body> </html>

Servlet

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; /** * @author DW-CHEN * 手动将获取的请求数据封装到对象中 */ @WebServlet("/servletDemo20") public class Demo20 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); String name = req.getParameter("name"); String password = req.getParameter("password"); String[] hobbies = req.getParameterValues("hobby"); Student student = new Student(name, password, hobbies);//封装到学生对象中 System.out.println(student); writer.write(String.valueOf(student)); writer.close(); } } //学生对象 class Student{ private String name; private String password; private String[] hobby; public Student() { } public Student(String name, String password, String[] hobby) { this.name = name; this.password = password; this.hobby = hobby; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String[] getHobby() { return hobby; } public void setHobby(String[] hobby) { this.hobby = hobby; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", password='" + password + '\'' + ", hobby=" + Arrays.toString(hobby) + '}'; } }

反射封装的方式

html测试页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> <style> .div1{ width: 1200px; height: 800px; border: solid 1px red; } .div2{ width: 600px; height: 50%; margin-left: 500px; margin-top: 20px; } </style> </head> <body> <div class="div1"> <div class="div2"> <form action="/request/servletDemo21" method="get" autocomplete="off"> 姓名:<input type="text" name="name"><br/><br/> 密码:<input type="password" name="password"><br/><br/> 喜好:<input type="checkbox" name="hobby" value="play">玩游戏 <input type="checkbox" name="hobby" value="sleep">睡觉<br/><br/> <button type="submit">注册</button> </form> </div> </div> </body> </html>

Servlet

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Map; import java.util.Set; /** * @author DW-CHEN * 通过反射的方式将获取到的请求数据封装到对象中 */ @WebServlet("/servletDemo21") public class Demo21 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); Student1 student = new Student1(); Map<String, String[]> parameterMap = req.getParameterMap();//获取到所有的请求参数值,以键值对的方式 Set<String> keySet = parameterMap.keySet(); for (String name : keySet) { String[] parameterValues = req.getParameterValues(name);//根据键获取对应的所有值 try { PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, student.getClass());//获取学生对象的属性描述器 Method writeMethod = propertyDescriptor.getWriteMethod();//通过属性描述器获取学生对象对应的setXXX方法 if (parameterValues.length > 1) {//判断根据键获取到的值是否时多个,如果是,则将它强转一下 writeMethod.invoke(student, (Object)parameterValues); }else { writeMethod.invoke(student, parameterValues); } } catch (IntrospectionException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } System.out.println(student); writer.write(student.toString()); writer.close(); } } //学生对象 class Student1{ private String name; private String password; private String[] hobby; public Student1() { } public Student1(String name, String password, String[] hobby) { this.name = name; this.password = password; this.hobby = hobby; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String[] getHobby() { return hobby; } public void setHobby(String[] hobby) { this.hobby = hobby; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", password='" + password + '\'' + ", hobby=" + Arrays.toString(hobby) + '}'; } }

工具类封装的方式

使用工具类需要到入commons-beanutils-1.9.2.jar/commons-logging-1.1.1.jar包,下载地址:https://download.csdn.net/download/qq_42795277/12805872

html测试页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> <style> .div1{ width: 1200px; height: 800px; border: solid 1px red; } .div2{ width: 600px; height: 50%; margin-left: 500px; margin-top: 20px; } </style> </head> <body> <div class="div1"> <div class="div2"> <form action="/request/servletDemo22" method="get" autocomplete="off"> 姓名:<input type="text" name="name"><br/><br/> 密码:<input type="password" name="password"><br/><br/> 喜好:<input type="checkbox" name="hobby" value="play">玩游戏 <input type="checkbox" name="hobby" value="sleep">睡觉<br/><br/> <button type="submit">注册</button> </form> </div> </div> </body> </html>

学生类

package cn.cdw.demo; import java.util.Arrays; public class Student2{ private String name; private String password; private String[] hobby; public Student2() { } public Student2(String name, String password, String[] hobby) { this.name = name; this.password = password; this.hobby = hobby; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String[] getHobby() { return hobby; } public void setHobby(String[] hobby) { this.hobby = hobby; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", password='" + password + '\'' + ", hobby=" + Arrays.toString(hobby) + '}'; } }

Servlet

package cn.cdw.demo; import org.apache.commons.beanutils.BeanUtils; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Map; /** * @author DW-CHEN * 通过工具类将请求数据封装到对象中 * 注意:需要在web目录下导入commons-beanutils-1.9.2.jar/commons-logging-1.1.1.jar包 */ @WebServlet("/servletDemo22") public class Demo22 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Student2 student = new Student2(); Map<String, String[]> parameterMap = req.getParameterMap(); try { BeanUtils.populate(student,parameterMap); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } System.out.println(student); resp.getWriter().write(student.toString()); } }

请求对象的流对象获取请求信息

方法名说明BufferedReader getReader获取字符输入流ServletInputStream getInputStream()获取字节输入流

html测试页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> <style> .div1{ width: 1200px; height: 800px; border: solid 1px red; } .div2{ width: 600px; height: 50%; margin-left: 500px; margin-top: 20px; } </style> </head> <body> <div class="div1"> <div class="div2"> <form action="/request/servletDemo23" method="get" autocomplete="off"> 姓名:<input type="text" name="name"><br/><br/> 密码:<input type="password" name="password"><br/><br/> 喜好:<input type="checkbox" name="hobby" value="play">玩游戏 <input type="checkbox" name="hobby" value="sleep">睡觉<br/><br/> <button type="submit">注册</button> </form> </div> </div> </body> </html>

通过字符对象获取请求数据,注意:请求方式必须为post方式

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; /** * @author DW-CHEN * 通过流对象获取请求数据 * * 通过字符对象获取请求数据,注意:请求方式必须为post方式 */ @WebServlet("/servletDemo23") public class Demo23 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { BufferedReader bufferedReader = req.getReader(); String data; while ((data = bufferedReader.readLine()) != null) { System.out.println(data); resp.getWriter().write(data); } } }

通过字节流对象获取请求数据,注意:请求方式必须为post方式

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * 通过流对象获取请求数据 * * 通过字节流对象获取请求数据,注意:请求方式必须为post方式 */ @WebServlet("/servletDemo24") public class Demo24 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletInputStream inputStream = req.getInputStream(); byte[] bytes = new byte[1024]; int len; while ((len = inputStream.read(bytes)) != -1){ System.out.println(new String(bytes,0,len)); resp.getWriter().write(new String(bytes,0,len)); } } }

请求方式乱码问题

GET方式

没有乱码问题,tomcat8版本后已经解决

POST方式

有乱码问题,可以通过setCharacterEncoding()方法来解决 req.setCharacterEncoding("UTF-8");//指定编码

请求域

请求域(request域):可以在一次请求范围进行共享数据一般用于请求转发的多个资源中共享数据

请求对象操作共享数据方法

方法名说明void setAttribute(String name,Object value)向请求域对象中存储数据Object getAttribute(String name)通过名称获取请求域对象中的数据void removeAttribute(String name)通过名称移请求域对象中的数据

请求转发

就是客户端的一次请求到达后,发现需要借助其他的Servlet来实现功能

特点:

浏览器地址栏不变域对象中的数据不会丢失负责转发的Servlet转发前后的响应正文会丢失由转发的目的地来响应客户端 方法名说明RequestDispatcher getRequestDispatcher(String name)获取请求调度对象void forward(ServletRequest req,ServletResponse resq)实现转发 package cn.cdw.demo; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * * 请求域/请求转发 */ @WebServlet("/servletDemo26") public class Demo26 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setAttribute("data","我是request域的共享数据"); RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servletDemo27");//设置转发到 /request/servletDemo27 requestDispatcher.forward(req, resp); } } package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * * 请求转发到这个类进行处理 */ @WebServlet("/servletDemo27") public class Demo27 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Object data = req.getAttribute("data");//根据名称获取request域的共享数据 System.out.println("Demo27类方法执行了,收到的request域的共享数据为:"+data); resp.getWriter().write("TEST SUCCESS....."); } }

请求包含

方法名说明RequestDispatcher getRequestDispatcher(String name)获取请求调度对象void include(ServletRequest req,ServletResponse resq)实现包含 package cn.cdw.demo; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * 请求包含 */ @WebServlet("/servletDemo28") public class Demo28 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("我自己..."); resp.getWriter().write("mySelf...."+"\r\n"); RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servletDemo29");//设置请求包含的地址 requestDispatcher.include(req, resp); } } package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * 请求包含 */ @WebServlet("/servletDemo29") public class Demo29 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("我是另一个功能了...."); resp.getWriter().write("other...."); } }

响应对象Response

响应:回馈结果,就是服务端给客户端浏览器返回结果响应对象:就是在项目中使用发送响应的对象

常见的状态码

状态码说明200成功302重定向304请求资源未改变,使用缓存400请求错误,常见于请求参数错误404请求资源未找到405请求方式不支持500服务器错误

响应对象的流对象

方法名说明ServletOutputStream getOutputStream()获取响应字节输出流对象PrintWriter getWriter()获取响应字符输出流对象void setContentType(“text/html;charset=UTF-8”)设置响应内容类型,解决中文乱码问题

response 字节流方式响应消息

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * * 乱码问题 * * response 字节流方式响应消息 */ @WebServlet("/servletDemo30") public class Demo30 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8");//统一设置编码 String str = "我是响应消息"; ServletOutputStream outputStream = resp.getOutputStream(); outputStream.write(str.getBytes("UTF-8")); } }

response 字符流方式响应消息

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * * 乱码问题 * * response 字符流方式响应消息 */ @WebServlet("/servletDemo31") public class Demo31 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); String str = "我是字符流方式的响应消息"; PrintWriter writer = resp.getWriter(); writer.write(str); } }

response字节流方式响应图片

package cn.cdw.demo; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; /** * @author DW-CHEN * * response字节流方式响应图片 */ @WebServlet("/servletDemo32") public class Demo32 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = req.getServletContext(); String realPath = servletContext.getRealPath("/img/1.jpg");//需要根据ServletContext对象获取到资源的绝对路径,不然读取不到资源 BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(realPath));//读取资源文件 ServletOutputStream outputStream = resp.getOutputStream();//获取响应字节流 byte[] bytes = new byte[1024]; int len; while ((len = bufferedInputStream.read(bytes)) != -1) { outputStream.write(bytes, 0, len); } bufferedInputStream.close(); } }

设置缓存

对于不经常变化的数据,我们可以 设置合理的缓存时间 方法名说明void setDataHeader(String name,long time)设置消息头添加缓存 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * * 设置缓存时间 */ @WebServlet("/servletDemo33") public class Demo33 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); String str = "我要作为缓存的数据...."; resp.setDateHeader("Expires",System.currentTimeMillis() + 1000*1*60*10);//缓存10分钟,设置缓存时间为当前访问时间加上10分钟 resp.getWriter().write(str); } }

定时刷新

就是过了指定的时间后,页面自动进行跳转 方法名说明void setHeader(String name,Stirng value)设置消息头刷新 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * response 定时刷新 */ @WebServlet("/servletDemo34") public class Demo34 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); String str = "3秒后自动跳回注册页面"; resp.getWriter().write(str); resp.setHeader("Refresh","3;URL=/response/html/register.html");//注意:跳转路径需要加访问虚拟路径 } }

请求重定向

就是客户端的一次请求到达后,发现需要借助其它的Servlet来实现功能

特点:

浏览器地址栏会发生改变两次请求请求域对象中不能共享数据可以重定向到其它服务器

重定向实现的原理:

设置响应状态码为302 resp.setStatus(302); 设置响应的资源路径(响应到哪里,通过响应头location来指定) resp.setHeader("location","/request/servletDemo")

响应对象重定向的方法

方法名说明void sendRedirect(String name)设置重定向 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * 请求重定向 * * 注意:它的请求域是不可以共享数据的 */ @WebServlet("/servletDemo35") public class Demo35 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); req.setAttribute("data","我是共享数据..........."); System.out.println("我自己执行了...."); //重定向 resp.sendRedirect(req.getContextPath()+"/servletDemo36");//需要动态获取虚拟路径拼接上映射路径 } } package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * 请求重定向 * * 注意:它的请求域是不可以共享数据的 */ @WebServlet("/servletDemo36") public class Demo36 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); Object data = req.getAttribute("data"); System.out.println("共享数据:"+data); writer.write("共享数据:" + data);//重定向是不可以共享数据的,所以为null System.out.println("其他方法执行了...."); } }

response 响应对象下载文件

package cn.cdw.demo; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; /** * @author DW-CHEN * response 响应对象下载文件 */ @WebServlet("/servletDemo37") public class Demo37 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); ServletContext servletContext = req.getServletContext(); String realPath = servletContext.getRealPath("/img/1.jpg"); BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(realPath)); resp.setHeader("Content-Type","application/octet-stream");//设置支持类型响应头参数,Content-Type:表示支持类型;application/octet-stream:表示应用的类型为字节流 resp.setHeader("Content-Disposition","attachment;filename=1.jpg");//设置下载处理响应头参数,Content-Disposition:表示处理的形式;attachment:表示以附件的形式下载;filename:表示指定下载文件的名称(可以自定义命名) ServletOutputStream outputStream = resp.getOutputStream(); byte[] bytes = new byte[1024]; int len; while ((len = bufferedInputStream.read(bytes)) != -1) { outputStream.write(bytes, 0, len); } bufferedInputStream.close(); } }

Cookie

会话:浏览器和服务器之间的多次请求和响应Cookie:客户端会话管理技术作用:可以保存客户端访问网站的相关内容,从而保证每次访问时先从本地缓存中获取,以此提高效率

Cookie的属性

属性名作用nameCooke的名称valueCookie的值(不支持中文)pathCookie的路径domainCooke的域名maxAgeCookie的存活时间varsionCookie的版本号commentCookie的描述

Cookie方法

方法名说明Cookie(String name,String value)构造方法创建对象属性对应的get/set方法赋值和获取值

Cookie的添加和获取

添加:HttpServletResponse 方法名说明void addCookie(Cookie cookie)向客户端添加Cookie 获取:HttpServletRequest 方法名说明Cookie[] getCookies()获取所有的Cookie

通过cookie记录最后访问时间

package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; /** * @author DW-CHEN * 通过cookie记录最后访问时间 */ @WebServlet("/servletDemo40") public class Demo40 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); Cookie cookie = new Cookie("time", System.currentTimeMillis()+"");//创建一个Cookie记录最后访问时间 cookie.setMaxAge(3600);//设置cookie最大存活时间(单位为秒) resp.addCookie(cookie);//添加cookie到客户端 Cookie[] cookies = req.getCookies();//获取所有客户端cookie for (Cookie cookie1 : cookies) { if ("time".equals(cookie1.getName())) {//根据名称找到记录最后访问时间的cookie String value = cookie1.getValue();//获取到记录最后访问时间的值 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");//进行一下时间格式化 String lastTime = simpleDateFormat.format(new Date(Long.parseLong(value)));//时间格式化最后访问时间格式 writer.write("最后访问时间为:"+lastTime); } } } }

Cookie的细节

数量限制:每个网站最多只能有20个Cookie,且大小不能超过4KB,所有网站的Cookie总数不能超过300个名称限制:Cookie的名称只能包含ASSCCI码表中的字母,数字字符,不能包含逗号,分号,空格,不能以$符号开头,Cookie的值不支持中文存活时间限制:setMaxAge(),如果是负整数,那么在当前会话有效,浏览器关闭则清除;如果是0则表示立即清除;如果是正整数,那么就是以秒为单位设置存活时间访问路径限制:默认路径,取自第一次访问的资源路径的前缀,只要以这个路径开头就能访问到;设置路径:setPath()方法设置指定的路径

Session

HttpSession:服务端会话管理技术(本质也是采用客户端会话管理技术) 作用:可以实现数据共享

HttpSession是Servlet规范中四大域对象之一

域对象说明ServletContext应用域,在整个应用之间实现数据共享ServletRequest请求域,在当前请求或请求转发之间实现数据共享HttpSession会话域,在当前会话访问之间实现数据共享

HttpSession常用方法

方法名说明void setAttribute(String name,Object value)设置共享数据Object getAttribute(String name)获取共享数据void removeAttribute(String name)移除共享数据String getId()获取唯一标识名称void Invalidate()让session立即生效

HttpSession获取

HttpSession实现类对象是通过HttpServletRequest对象来获取的 方法名说明HttpSession getSession()获取HttpSession对象HttpSession getSession(boolean create)获取HttpSession对象,未获取到是否自动创建 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * session * * 通过session域设置共享数据,然后另一个servlet获取这个session域的共享数据 */ @WebServlet("/servletDemo41") public class Demo41 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); HttpSession session = req.getSession(); session.setAttribute("data","我是Session域的共享数据...."); writer.write("设置session域的的共享数据成功...."+"<br/>"); writer.write(session.toString()+"<br/>"); writer.write(session.getId()+"<br/>"); } } package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * session */ @WebServlet("/servletDemo42") public class Demo42 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); HttpSession session = req.getSession(); Object data = session.getAttribute("data"); writer.write("session域的共享数据为:" + data+"<br/>"); writer.write(session.toString()+"<br/>"); writer.write(session.getId()+"<br/>"); } }

HttpSession的细节

浏览器禁用Cookie

方式一:通过提示信息告知用户 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * 处理浏览器cookie功能关闭后影响session对象问题 * * 方式一:提示用户打开cookie功能 */ @WebServlet("/servletDemo43") public class Demo43 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); HttpSession session = req.getSession(false);//当没有session域时不自动创建session对象 if (session == null) { writer.write("为了不影响您的使用,请把浏览器的cookie功能打开"); } writer.write("正常使用...."); } } 方式二:访问时拼接jsessionid标识,通过encodeURL()方法重写地址 package cn.cdw.demo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; /** * @author DW-CHEN * 处理浏览器cookie功能关闭后影响session对象问题 * * 方式二:实现url重写,在请求路径后拼接上(;jssionid=session的唯一标识id) 不建议使用 */ @WebServlet("/servletDemo44") public class Demo44 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); HttpSession session = req.getSession(); writer.write(session.toString()+"<br/>"); writer.write(session.getId()+"<br/>"); writer.write("<a href='"+resp.encodeURL("http://localhost:8080/session/servletDemo43")+"'>点击我<a/>"); } }

钝化和活化:

钝化:序列化,把长时间不用,但还不到过期时间的HttpSession进行序列化写到磁盘上活化:相反的状态

什么时候钝化

第一种情况:当访问量很大时,服务器会根据getLastAccessTie来进行排序,对长时间不用但还没有过期时间的HttpSession进行序列化第二种情况:当服务器进行重启的时候,为了保持客户HttpSession中的数据,也要对其进行序列化

注意:HttpSession的序列化是由服务器自动完成的

JSP

JSP(Java Server Pages):是一种动态网页技术标准

JSP是基于Java语言的,它的本质就是Servlet生成的Java文件目录:C:\Users\Administrator.IntelliJIdea2019.2\system\tomcat\Tomcat_8_5_31_webDemo\work\Catalina\localhost\request\org\apache

JSP语法

JSP注释:<%-- 注释内容 --%>Java代码块:<%Java代码%>JSP表达式:<%=表达式%>JSP声明:<%!声明变量或方法%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>JSP 标题</title> </head> <body> <% System.out.println("jsp 代码块"); out.println("jsp代码块"); %> <%--jsp代码块--%> <br/> <%="jsp表达式"%><%--jsp表达式,相当于out.println("jsp表达式");--%> <br/> <%! String str = "jsp声明";%><%--jsp声明,注意<%! %>:表示声明成员变量或方法,<% %>:表示声明局部变量--%> <%out.println(str);%> </body> </html>

JSP指令

page指令

<%@page 属性名=属性值 属性名=属性值…%> 属性名说明contentType响应正文支持的类型和设置编码格式language使用的语言,默认是javaerrorPage当前页面出现异常后跳转的页面isErrorPage是否抓住异常,如果为true,则页面种就可以使用异常对象,默认为falseimport导包session是否创建HttpSession对象,默认为truebuffer设定JspWriter输出jsp内容缓存的大小,默认为8KBpageEncoding翻译jsp时所用的编码格式isElgnored是否忽略EL表达式,默认为false

include指令

<%@include file=包含的页面%>

taglib指令

可以引入外部标签库<%@taglib url=标签库的地址 prefix=前缀名称%>

JSP细节

九大隐式对象

隐式对象的名称代表的实际对象requestjavax.servlet.http.HttpServletRquestresponsejavax.servlet.http.HttpServletResponsesessionjavax.servelt.http.HttpSerssionapplicationjavax.servlet.ServletContextpagejava.lang.Objectconfigjavax.servlet.ServletConfigexceptionjava.lang.Throwableoutjavax.servlet.jsp.JspWriterpageContextjavax.servlet.jsp.PageContext

PageContext对象

PageContext对象是jsp独有的,Servlet中没有是四大域对象之一的页面域对象,还可以操作其他三个域对象中的属性还可以获取其他八大隐式对象生命周期是随着JSP的创建而存在,随着JSP的结束而消失,每个JSP页面都有一个PageContext对象

四大域对象

域对象名称说明pageContext页面域对象,范围最小,只能当前页面使用ServletRequest请求域对象,请求范围,一次请求或当前请求转发用;请求转发后,再次转发的请求域会丢失HttpSession会话域对象,多次请求数据共享时使用,但不同的客户端不能共享ServletContext应用域,范围最大,整个应用都可以使用;尽量少用,如果对数据有修改需要做同步处理

EL表达式

EL(Expression Language):表达式语言作用:在jsp页面中获取数据,让我们的JSP脱离Java代码块和JSP表达式语法:${表达式内容} <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>el表达式</title> </head> <body> <%request.setAttribute("data","我是测试数据");%> Java代码块:<%out.println(request.getAttribute("data"));%> <br/> jsp表达式:<%=request.getAttribute("data")%><br/> el表达式:${data} </body> </html>

EL表达式获取数据

获取基本类型的数据获取自定义对象类型的数据获取数组类型的数据获取list集合类型的数据获取map结婚类型的数据

自定义类

package cn.cdw.demo; public class Student3{ private String name; private Integer age; private String address; public Student3() { } public Student3(String name, Integer age, String address) { this.name = name; this.age = age; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } <%@ page import="cn.cdw.demo.Student3" %> <%@ page import="java.util.ArrayList" %> <%@ page import="java.util.Map" %> <%@ page import="java.util.HashMap" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>EL 获取不同的数据</title> </head> <body> ===================获取基本数据类型============================<br/> <% String s = "你好 el...."; pageContext.setAttribute("str", s); %> ${str}<br/><br/> ===================获取自定义对象类型============================<br/> <% Student3 student = new Student3("小明", 12, "深圳"); pageContext.setAttribute("student", student); %> 学生对象:${student}<br/> 学生姓名:${student.name}<br/> 学生年龄:${student.age}<br/> 学生地址:${student.address}<br/><br/> ===================获取数组类型============================<br/> <% int[] arr = {12, 22}; pageContext.setAttribute("arr", arr); %> 数组对象:${arr}<br/> 数组的第一个元素:${arr[0]}<br/> 数组的第二个元素:${arr[1]}<br/><br/> ===================获取list集合数据类型============================<br/> <% ArrayList<Student3> arrayList = new ArrayList<>(); arrayList.add(new Student3("小李", 21, "深圳")); arrayList.add(new Student3("小红", 22, "北京")); arrayList.add(new Student3("小明", 43, "上海")); pageContext.setAttribute("arrayList", arrayList); %> 集合对象:${arrayList}<br/> 集合中的第一个学生对象:${arrayList[0]}<br/> 集合中的第一个学生对象的姓名:${arrayList[0].name}<br/> 集合中的第二个学生对象的地址:${arrayList[1].address}<br/><br/> ===================获取map集合数据类型============================<br/> <% Map<String, Student3> map = new HashMap<>(); map.put("stu1", new Student3("小明", 12, "深圳")); map.put("stu2", new Student3("小李", 22, "北京")); pageContext.setAttribute("map", map); %> map集合:${map}<br/> map集合中Kye为stu2的学生对象:${map.stu2}<br/> map集合中Kye为stu2的学生对象的姓名:${map.stu2.name}<br/> map集合中Kye为stu2的学生对象的年龄:${map.stu2.age}<br/> map集合中Kye为stu2的学生对象的地址:${map.stu2.address}<br/> </body> </html>

El表达式注意事项

EL 表达式没有空指针异常EL表达式没有索引越界异常EL表达式没有字符串拼接

EL表达式运算符

关系运算符

运算符作用== 或者 eq等于!= 或者 ne不等于< 或者 lt小于> 或者 gt大于<= 或者 le小于等于>= 或者 ge大于等于

逻辑运算符

运算符作用&& 或者 and并且|| 或者 or或者! 或者 not取反

其他运算符

运算符作用empty判断对象是否空,判断字符串是否为空字符串,判断容器元素是否为0条件 ? 表达式1 : 表达式2三元运算符

EL 表达式使用细节

EL表达式能够获取四大域对象的数据,根据名称从小到大在域对象中查找还可以获取JSP其他八个隐式对象,并调用对象的方法

EL表达式隐式对象

隐式对象名称说明pageContext对应的JSP隐式对象是PageContext,功能完全相同applicationScope操作应用域数据sessionScope操作会话域对象数据requestScope操作请求域对象数据pageScope操作页面域对象数据header获取请求头数据headerValues获取请求头数据(多个值)param获取请求参数数据paramValues获取请求参数数据(多个值)initParam获取全局配置参数数据cookie获取Cookie对象 <%@ page import="java.util.Collection" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>EL表达式隐式对象</title> </head> <body> ========================================pageContext获取四大域的对象的数据,从小到大查找============================================<br/> <% pageContext.setAttribute("data", "pageContext"); request.setAttribute("data", "request"); session.setAttribute("data", "session"); application.setAttribute("data","application"); %> ${data}<br/><br/> ========================================pageContext获取JSP其他八大隐式对象,并调用对象的方法============================================<br/> <% String contextPath = request.getContextPath(); out.println("jsp的request隐式对象获取访问虚拟路径:"+contextPath); %> <br/> el表达式获取jsp的request隐式对象获取访问虚拟路径:${pageContext.request.contextPath}<br/><br/> ===========================pageScope,requestScope,sessionScope,applicationScope操作四大域对象数据=========================================================<br/> <% pageContext.setAttribute("data", "pageContext"); request.setAttribute("data", "request"); session.setAttribute("data", "session"); application.setAttribute("data","application"); %> ${applicationScope.data}<br/> ${sessionScope.data}<br/> ${requestScope.data}<br/> ${pageScope.data}<br/><br/> ===========================header,headerValues=========================================================<br/> 获取accept-encoding这个请求头的所有值:${header["accept-encoding"]}<br/><br/> 获取所有请求头的数据,map集合格式:${headerValues}<br/><br/> 获取所有请求头的数据,map集集合中的键为accept-encoding的所有值:${headerValues["accept-encoding"]}<br/><br/> ===========================param,paramValues获取请求参数值=========================================================<br/> 获取请求属性为name的值:${param.name}<br/> 获取所有的请求参数,map集合格式:${paramValues}<br/> 获取请求属性为hobby的所有值,数组格式:${paramValues.hobby}<br/> 获取请求属性为hobby的所有值的第一个参数:${paramValues.hobby[0]}<br/> 获取请求属性为hobby的所有值的第二个参数:${paramValues.hobby[1]}<br/><br/> =============================initParam获取配置全局参数的数据,全局参数在web.xml中配置=======================================================<br/> 获取配置全局参数名为encoding的数据:${initParam["encoding"]}<br/><br/> =============================cookie,获取cookie对象=======================================================<br/> 获取所有cookie对象,map集合格式:${cookie}<br/> 获取cookie名为JSESSIONID的对象:${cookie.JSESSIONID}<br/> 获取cookie名为JSESSIONID的name:${cookie.JSESSIONID.name}<br/> 获取cookie名为JSESSIONID的value:${cookie.JSESSIONID.value} </body> </html>

JSTL

JSTL(Java Server Pages Standarded Tag Library):JSP标准标签库开发人员可以利用这些标签取代JSP页面上的Java代码,从而提过程序的可读性,降低程序的维护性难度 组成说明core核心标签库,通用的逻辑处理fmt国际化,不同地域显示不同语言functionsEL函数,EL表达式可以使用的方法sql操作数据库xml操作XML

JSTL核心标签库

使用JSTL需要下载的jstl-1.2.jar包,下载地址:https://download.csdn.net/download/qq_42795277/12804268

标签库名称说明<标签名:if>流程控制,用于条件判断<标签名:choose> ,<标签名:when>,<标签名:otherwise>流程控制,用于多条件判断<标签名:forEach>迭代遍历,用于循环遍历 <%@ page import="java.util.ArrayList" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <html> <head> <title>jstl使用</title> </head> <body> =======================jstl的使用,需要在web下的WEB-INF添加jstl-1.2.jar包===============================================================<br/> <% String str = "A"; pageContext.setAttribute("data", str); %> =======================if判断语句===============================================================<br/> <c:if test="${'A'.equals(data)}"> 你的成绩优秀.... </c:if><br/><br/> =======================多条件判断语句===============================================================<br/> <c:choose> <c:when test="${'A' eq data}">你的成绩优秀....</c:when> <c:when test="${'B' eq data}">你的成绩很好....<</c:when> <c:when test="${'C' eq data}">你的成绩一般....</c:when> <c:when test="${'D' eq data}">继续努力....</c:when> <c:otherwise>数据错误..</c:otherwise> </c:choose><br/><br/> =======================遍历集合===============================================================<br/> <% ArrayList<Integer> arrayList = new ArrayList<>(); arrayList.add(12); arrayList.add(22); arrayList.add(33); pageContext.setAttribute("arrayList", arrayList); %> <c:forEach items="${arrayList}" var="num"> ${num}<br/> </c:forEach> </body> </html>

过滤器Filter

过滤器一般用于完成通用的操作,例如登录验证,统一编码处理,敏感字符过滤等等…

Filter的核心方法

Filter是一个接口,如果想实现过滤器的功能,必须实现该接口 方法名说明void init(FilterConfig config)初始化方法void doFilter(ServletRequet req,ServletResponse res,FilterChain chain)请求资源和响应资源过滤void destroy()销毁方法

FilterChain

FilterChain 是一个接口,代表过滤器链对象,由Servlet容器提供实现类对象,直接使用即可过滤器可以定义多个,就会组成过滤器链 方法名说明void doFilter(ServletRequest req,ServletResponse resp)放行方法 如果有多个过滤器,在第一个过滤器中调用下一个过滤器,以此类推,知道到达最终访问资源(过滤的顺序取决于配置过滤器映射的顺序)如果只有一个过滤器,放行时,就会直接到达最终访问资源

web.xml手动配置过滤器映射

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>/demo/index.jsp</welcome-file> </welcome-file-list> <!--配置过滤器Demo48--> <filter> <filter-name>filterNameDemo48</filter-name> <filter-class>cn.cdw.demo.Demo48</filter-class> </filter> <filter-mapping> <filter-name>filterNameDemo48</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>

注解的方式,使用过滤器统一处理编码问题

package cn.cdw.demo; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * 通过Filter过滤器解决多个资源写出中文乱码问题 */ @WebFilter("/*") //设置过滤拦截所有请求 public class Demo48 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { try { HttpServletRequest req = (HttpServletRequest)servletRequest; HttpServletResponse resp = (HttpServletResponse)servletResponse; req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); filterChain.doFilter(req, resp);//处理完成后放行 } catch (Exception e) { e.printStackTrace(); } } @Override public void destroy() { } }

过滤器生命周期

创建:当应用加载时实例化对象执行init初始化方法服务:对象提供服务的过程,执行doFilter方法销毁:当应用程序卸载时或服务停止的时候对象销毁,执行destroy方法

FilterConfig

FilterConfig是一个接口,代表过滤器的配置对象,可以加载一些初始化参数

方法名说明String getFilterName()获取过滤器对象名称String getInitParameter(String key)根据key获取valueEnueration<String> getInitParameterNames()获取所有的参数的keyServletContextgetServletContext()

web.xml

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>/demo/index.jsp</welcome-file> </welcome-file-list> <!--配置过滤器Demo51--> <filter> <filter-name>filterNameDemo51</filter-name> <filter-class>cn.cdw.demo.Demo51</filter-class> <!--配置初始化值--> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>name</param-name> <param-value>aaa</param-value> </init-param> </filter> <filter-mapping> <filter-name>filterNameDemo51</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> package cn.cdw.demo; import javax.servlet.*; import java.io.IOException; import java.util.Enumeration; /** * @author DW-CHEN * FilterConfig */ public class Demo51 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("======================获取过滤器名称========================"); String filterName = filterConfig.getFilterName(); System.out.println(filterName); System.out.println("\r\n"); System.out.println("\r\n"); System.out.println("=========================根据名称获取过滤器中的初始化值(web.xml中配置的过滤初始化值)==================================="); String encoding = filterConfig.getInitParameter("encoding"); System.out.println(encoding); System.out.println("\r\n"); System.out.println("\r\n"); System.out.println("=========================获取过滤器中的所有初始化值(web.xml中配置的过滤初始化值)==================================="); Enumeration<String> initParameterNames = filterConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()) { String name = initParameterNames.nextElement(); System.out.println(name + " : " + filterConfig.getInitParameter(name)); } System.out.println("\r\n"); System.out.println("\r\n"); System.out.println("=========================获取上下文对象,然后可以调用上下文对象相关方法使用==================================="); ServletContext servletContext = filterConfig.getServletContext(); String contextPath = servletContext.getContextPath(); System.out.println(contextPath); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { } @Override public void destroy() { } }

过滤器的五种拦截行为

Filter 过滤器默认拦截的是请求,但是在实际开发中,我们还有请求转发和请求包含,以及由服务器触发调用的全局错误页面,默认情况下过滤器是不参与过滤的,如果需要使用过滤器,需要进行配置

拦截方式配置

web.xml

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>/demo/index.jsp</welcome-file> </welcome-file-list> <!-- 配置过滤器Demo53--> <filter> <filter-name>filterNameDemo53</filter-name> <filter-class>cn.cdw.demo.Demo53</filter-class> <async-supported>true</async-supported><!--配置开启异步支持,当dispatcher为ASYNC时需要进行配置开启异步支持--> </filter> <filter-mapping> <filter-name>filterNameDemo53</filter-name> <url-pattern>/index.jsp</url-pattern> <dispatcher>REQUEST</dispatcher><!--过滤请求,默认值--> <dispatcher>ERROR</dispatcher><!--过滤全局错误页面:当由服务器调用全局错误页面时进行过滤工作--> <dispatcher>FORWARD</dispatcher><!--过滤请求转发,当请求转发时,过滤器工作--> <dispatcher>INCLUDE</dispatcher><!--过滤请求包含,当请求包含时,过滤器工作;它只能过滤动态包含,jsp的include指令是静态包含--> <dispatcher>ASYNC</dispatcher><!--过滤异步类型,它需要我们在filter标签中配置开启异步支持--> </filter-mapping> <!--配置错误全局页面--> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/err/err.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/err/err.jsp</location> </error-page> </web-app>

Servlet,看如果修改拦截配置,测试访问servlet看过滤器是否执行

package cn.cdw.demo; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * servlet * 过滤器的五种拦截行为 */ @WebServlet("/servletDemo52") public class Demo52 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // int i = 1 / 0; //测试出现异常,是否执行过滤器,注意测试时修改一下拦截对应的路径 System.out.println("Demo52servlet执行了...."); //req.getRequestDispatcher("/index.jsp").forward(req, resp);//测试进行转发时,是否执行过滤器,注意测试时修改一下拦截对应的路径 req.getRequestDispatcher("/index.jsp").include(req, resp);//测试进行包含时,是否执行过滤器,注意测试时修改一下拦截对应的路径 } }

过滤器

package cn.cdw.demo; import javax.servlet.*; import java.io.IOException; /** * @author DW-CHEN * 过滤器的五种拦截行为 */ public class Demo53 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("过滤器Demo53执行了......."); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }

监听器Listener

所有的监听器都是基于观察者模式设计的在程序中,可以对对象的创建销毁,域对象中的属性变化,会话相关的内容进行监听Servlet规范中共计8个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成

监听对象的

ServletContextListenerHttpSessionListenerServletRequestListener

监听属性变化的

ServletContextAttributeListenerHttpSessionAttributeListenerServletRequestAttributeListener

监听会话相关感知型

HttpSessionBindingListenerHttpSessionActivationListener

组成

事件源:触发事件的对象事件:触发的动作,封装了事件源监听器:当事件源触发事件后,可以完成功能

监听对象

package cn.cdw.demo; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; /** * @author DW-CHEN * 监听ServletContext对象的初创建和销毁 */ @WebListener public class Demo54 implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("ServletContext对象创建了,对象为:" + servletContextEvent.getServletContext()); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("ServletContext对象销毁了...."); } }

监听ServletContext上下文对象的监听器

ServletContextListener:用于监听ServletContext对象的创建和销毁 方法名说明void contextInitialized(ServletContextEvent sec)对象创建的时候执行该方法void contextDestroyed(ServletContextEvent sce)对象销毁时执行该方法

参数:ServletContextEvent 代表事件对象,事件对象中封装了事件源,也就是ServletContext,真正的事件指的是创建或销毁ServletContext对象的操作

监听HttpSession会话对象的监听器

HttpSessionListener:用于监听HttpSession对象的创建和销毁 方法名说明void sessionCreated(HttpSessionEvent se)对象创建时执行该方法void sessionDestroyed(HttpSessionEvent se)对象销毁时执行该方法

参数:HttpSessionEvent 代表事件对象,事件对象中封装了事件源,也就是HttpSession,真正的事件指的时创建或销毁HttpSession对象的操作

监听ServletRequest请求对象的监听器

ServletRequestListener:用于监听ServletRequest对象的创建和销毁

方法名说明void requestInitialized(ServletRequestEvent sre)对象创建的时候执行该方法void requestDestroyed(ServletRequestEvent sre)对象销毁时执行该方法

参数:ServletRequestEvent 代表事件对象,事件对象中封装了事件源,也就是ServletRequest,真正的事件指的时创建或销毁ServletRequest对象的操作

监听属性

package cn.cdw.demo; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.annotation.WebListener; /** * @author DW-CHEN * 监听应用域对象属性变化 */ @WebListener public class Demo55 implements ServletContextAttributeListener { @Override public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("应用域添加了属性值为:" + servletContextAttributeEvent.getServletContext().getAttribute("name")); } @Override public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("应用域修改了属性值为:" + servletContextAttributeEvent.getServletContext().getAttribute("name")); } @Override public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("应用域删除了属性,值为:" + servletContextAttributeEvent.getServletContext().getAttribute("name")); } }

测试Servlet

package cn.cdw.demo; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author DW-CHEN * 测试应用域对象属性发生改变,监听器是否执行 */ @WebServlet("/servletDemo56") public class Demo56 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = req.getServletContext(); servletContext.setAttribute("name", "添加了数据"); servletContext.setAttribute("name", "修改了数据"); servletContext.removeAttribute("name");//删除了数据 } }

监听ServletContext应用域对象属性变化的监听器

ServletContextAttributeListener:用于监听ServletContext应用域中的属性变化 方法名说明void attributeAdded(ServletContextAttributeEvent scae)域中添加属性时执行该方法void attributeRemoved(ServletContextAttributeEvent scae)域中异常属性时执行该方法void attributeReplaced(ServletContextAttributeEvent scae)域中替换属性时执行该方法

参数:ServletContextAttributeEvent 代表事件对象,事件对象中封装了事件源,也就是ServletContex,真正的事件指的是添加,移除,替换应用域中的属性操作

监听HttpSession会话域对象属性变化的监听器

HttpSessionAttributeListener:用于监听HttpSession会话域中的属性变化 方法名说明void attributeAdded(HttpSessionBindingEvent se)域中添加属性时执行该方法void attributeRemoved(HttpSessionBindingEvent se)域中异常属性时执行该方法void attributeReplaced(HttpSessionBindingEvent se)域中替换属性时执行该方法

参数:HttpSessionBindingEvent 代表事件对象,事件对象中封装了事件源,也就是HttpSession,真正的事件指的是添加,移除,替换会话域中的属性操作

监听ServletRequest请求域对象属性变化的监听器

ServletRequestAttributeListener:用于监听ServletRequest请求域中的属性变化 方法名说明void attributeAdded(ServletRequestAttributeEvent srae)域中添加属性时执行该方法void attributeRemoved(ServletRequestAttributeEvent srae)域中异常属性时执行该方法void attributeReplaced(ServletRequestAttributeEvent srae)域中替换属性时执行该方法

参数:ServletRequestAttributeEvent 代表事件对象,事件对象中封装了事件源,也就是ServletRequest,真正的事件指的是添加,移除,替换请求域中的属性操作

监听会话相关的感知型监听器

HttpSessionBindingListener: 用于感知对象和会话域绑定的监听器 方法名说明void valueBound(HttpSessionBindingEvent event)数据添加到会话域中(绑定)是执行该方法void valueUnbound(HttpSessionBindingEvent event)数据从会话域中移除(解绑)时执行该方法

参数:HttpSessionBindingEvent 代表事件对象,事件对象中封装了事件源,也是是HttpSession,真正的事件指的是添加,移除会话域中的数据操作

HttpSessionActivationListener:用于感知会话域中对象钝化和活化的监听器 方法名说明void sessionWillPassivate(HttpSessionEven se)会话数据钝化时执行该方法void sessionDidActivate(HttpSessionEvent se)会话域中数据活化时执行该方法

参数:HttpSessionEvent代表事件对象,事件对象中封装了事件源,也就是HttpSession,正在的事件指的是会话域中数据钝化,活化操作

最新回复(0)