5# Servlet
问题
1.JDK和Tomcat兼容性问题
java.lang.UnsupportedClassVersionError: servletDemo/HelloWorldServlet has been compiled by a more recent version of the Java Runtime (class file version 59.0), this version of the Java Runtime only recognizes class file versions up to 52.0 (无法载入的.类 [servletDemo.HelloWorldServlet])
2.JDK和环境配置
3.Tomcat启动后一闪而过
4.Tomcat乱码问题
1.Servlet概述
- Servlet是使用Java语言编写的运行在服务器端的程序
- 狭义的Servlet: 指Java语言实现的一个接口;广义的Servlet: 指任何实现了这个Servlet接口的类
- Servlet的主要作用: 处理客户端传来的HTTP请求,并返回一个响应(它能处理的请求有doGet()和doPost()等方法)
- Servlet由Servlet容器提供,Servlet容器将Servlet动态的加载到服务器上
- Servlet容器指提供了Servlet功能的服务器(Tomcat)
- Servlet容器支持所有HTTP协议的请求和响应,与HTTP协议相关的Servlet使用HTTP请求和TTP响应与客户端进行交互
- 1.Servlet的请求首先会被HTTP服务器(Apache) 接收
- 2.HTTP服务器只负责静态HTML页面的解析,对于Servlet的请求转发给Servlet容器(Tomcat)
- 3.Servelt容器根据web.xml文件中的映射关系,调用相应的Servlet
- 4.Servlet将处理的结果返回给Servlet容器,并通过HTTP服务器将响应传输给客户端
- 5.针对Servlet的每次请求,Web服务器在调用service()方法之前都会创建两个对象,分别是HttpServletRequest和HttpServletResponse
- 6.HttpServletRequest用于封装HTTP请求信息,简称request对象;HttpServletResponse用于封装HTTP响应信息,简称response对象
- 7.在Web服务器运行阶段,每个Servlet都只会创建一个实例对象;而每次HTTP请求,Web服务器都会调用所请求Servlet实例的service()方法,重新创建一个request对象和response对象
2.Servlet生命周期
- 一个Servlet的生命周期由部署Servlet的容器来控制
- Servlet生命周期划分为3个阶段
- 1.初始化阶段
- 2.运行阶段
- 3.销毁阶段
1.初始化阶段
- 1.客户端向Servlet容器(Tomcat)发出HTTP请求要求访问Servlet
- 2.Servlet容器解析请求,检查内存中是否存在相应的Servlet对象
- 3.如果有直接使用该Servlet对象,如果没有则创建Servlet实例对象(class),然后调用init()方法实现Servlet的初始化工作
- 4.在Servlet的整个生命周期中,它的init()方法只被调用一次
2.运行阶段
- 1.Servelt容器为请求创建代表HTTP请求的ServletRequest对象和代表HTTP响应的ServletResponse对象
- 2.将它们作为参数传递给Servlet的service()方法
- 3.service()方法从ServletRequest对象中获得客户端请求信息并处理该请求,通过ServletResponse对象生成响应结果
- 4.在Servlet的整个生命周期内,对于Servlet的每一次请求,Servlet都会调用一次Servlet的service()方法,并且创建新的ServletRequest和ServletResponse对象;即service()方法在Servlet的整个生命周期中会被调用多次
3.销毁阶段
- 1.当服务器关闭或Web应用被移除出容器时,Servlet随着Web应用的销毁而销毁
- 2.在销毁Servlet之前,Servlet容器会调用Servlet的destroy()方法,以便让Servlet对象释放它所占用的资源
- 3.在Servlet的整个生命周期中,destroy()方法也只调用一次
- 4.Servlet对象一旦创建就会驻留在内存中等待客户端的访问,直到服务器关闭或Web应用被移除容器时,Servlet对象才销毁
4.自动加载Servlet程序
- 1.使Servlet在Tomcat启动时就自动加载并且初始化,需要使用web.xml中的
< load-on-startup>
元素- 2.
< load-on-startup>
元素是< servlet>元素的一个子元素,它用于指定Servlet被加载的时机和顺序- 3.
< load-on-startup>
元素的值必须是一个整数;如果这个值是一个负数,或者没有设定这个元素,Servlet容器将在客户端首次请求这个Servlet时加载它;如果这个值是正整数或0,Servlet容器将在Web应用启动时加载并初始化Servlet- 4.
< load-on-startup>
元素的值越小,它对应的Servlet就越先被加载package test; import java.io.IOException; import javax.servlet.GenericServlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class ServletTest6 extends GenericServlet{ /** * */ private static final long serialVersionUID = 1L; public void init(ServletConfig config) throws ServletException { System.out.println("auto load"); } @Override public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stube System.out.println("HelloWorld"); } public void destroy() { System.out.println("destroy"); } }
<servlet> <servlet-name>ServletTest6</servlet-name> <servlet-class>test.ServletTest6</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ServletTest6</servlet-name> <url-pattern>/ServletTest6</url-pattern> </servlet-mapping>
3.Servlet接口及其实现类
1.Servlet类的层次结构:
- 说明:
- Java API提供了javax.servlet和javax.servlet.http包,为编写Servlet提供了相应的接口和实现类。
- 编写所有的Servlet时必须直接或间接地实现javax.servlet.Servlet接口,该接口定义了Servlet的生命周期方法
- 一般采用间接实现,即通过javax.servlet.GenericServlet或javax.servlet.http.HttpServlet类派生
- 编写Servlet时要用到javax.servlet.HttpServlet类为javax.servlet.GenericServlet的子类
- GenericServlet是一个抽象类,该类为Servlet接口提供了部分实现,但它并没有实现HTTP请求处理
- HttpServlet是GenericServlet的子类,它继承了GenericServlet的所有方法,并对HTTP请求中的POST,GET等类型提供了具体的操作方法
- javax.servlet.GenericServlet类为java.lang.Object类的子类,并且实现了javax.servlet.Servlet接口,javax.servlet.ServletConfig接口,javax.io.Serializable接口
- 一般情况下要用到的javax.servlet.http.HttpServieRequest接口继承于javax.servlet.ServletRequest接口;javax.servlet.http.HttpServletResponse接口继承于javax.servlet.ServletResponse接口
2.Servlet接口与实现类
类/接口名 说明 Servlet接口 定义了Servlet必须实现的方法 HttpServlet类 提供Servlet接口的HTTP特定实现 HttpServletRequest接口 获得客户端的请求信息 HttpServletResponse接口 获得服务器端的响应信息 ServletContext接口 与相应的Servlet容器通信 ServletConfig接口 用于在Servlet初始化时向其传递信息 3.Servlet接口常用方法
方法名 功能 void init(ServletConfig config) 容器创建好Servlet对象后会调用该方法,在Servlet的生命周期中仅执行一次;该方法接收一个ServletConfig类型的参数,Servlet容器通过这个参数向Servlet传递初始信息 void service(ServletRequest request,ServletResponse response) 负责响应用户的请求,当容器接收到客户端访问Servlet对象的请求后,就会调用此方法;容器会构造一个表示客户端请求信息的ServletRequest对象和一个用于响应客户端请求信息的ServletResponse对象作为参数传递给service()方法;在该方法中,通过ServletRequest对象可以得到客户端的相关信息和请求信息,通过ServletResponse对象可以设置响应信息 void destroy 当服务器关闭或Servlet对象被移除时,容器会执行该方法,释放Servlet对象占用的资源 ServletConfig getServletConfig() 返回一个ServletConfig对象,该对象用来返回初始化参数和ServletContext接口提供有关Servlet的配置信息 String getServletInfo() 返回一个字符串,提供有关Servlet的信息;如:作者,版本,版权信息 4.HttpServlet类常用方法
方法名 功能 void doGet() 由Servlet引擎调用处理一个HTTP GET请求 void doPost() 由Servlet引擎调用处理一个HTTP POST请求 void doPut() 处理一个HTTP PUT请求,请求URI指出被载入的文件位置 void doDelete() 处理一个HTTP DELETE请求,请求URI指出资源被删除 void service() 将请求导向doGet(),doPost()等,一般不应该覆盖此方法 5.HttpServletRequest接口常用方法
方法名 功能 String getContextPath() 返回指定Servlet上下文(Web应用)的URI的前缀 Cookie[] getCookies() 返回与请求相关Cookie的一个数组 String getHeader(String name) 返回指定的HTTP头标 String getMethod 返回HTTP请求方法(如:GET,POST) String getQueryString() 返回查询字符串,即URI中"?"后面的部分 String getRequestedSessionId(返回客户端的会话ID) String getRequestURI() 返回统一资源标识符(URI)中的一部分,从"/"开始,包括上下文但不包括任意查询子串 String getServeltPath() 返回请求URI上下文后的子串 HttpSession getSession(boolean create) 返回当前HTTP会话,如果不存在,则创建一个新的会话,create参数为true boolean isRequestedSessionIdValid() 如果客户端返回的会话ID仍然有效,则返回true Object getAttribute(String name) 返回具有指定名字的请求属性 Enumeration getAttributeName() 返回请求中所以属性名的枚举值 String getCharacterEncoding() 返回请求所用的字符编码 Int getContentLength() 指定输入流的长度,如果未知则返回-1 String getParameter(String name) 返回指定参数,如果不存在,则返回null Enumeration getParameterName() 返回请求中所以参数名的一个枚举(可能为空) String[] getParameterValues(String name) 返回指定输入参数名的取值数组,如果不存在则返回null String getProtocol() 返回请求使用协议的名称和版本 String getServerName() 返回处理请求的服务器的主机名 String getServerPort() 返回接收主机正在监听的端口号 String getRemoteAddr() 返回客户端主机的数字型IP地址 String getRemoteHost() 返回客户端主机名 void setAttribute(String name,Object obj) 以指定名称保存请求中指定对象的引用 void removeAttribute(String name) 从请求中删除指定属性 6.HttpServletResponse接口常用方法
方法名 功能 void addCookie(Cookie cookie) 将一个Set-Cookie头标加入到响应 void addDateHeader(String name,long date) 使用指定日期加入带有指定名字的响应头标 void setHeader(String name,String value) 设置具有指定名字和取值的一个响应头标 boolean containHeader(String name) 判断响应是否包含指定名字的头标 void setStatus(int status) 设置响应状态码为指定值 String getCharacterEncoding() 返回响应使用字符编码的名称 OutputStream getOutputStream() 返回一个记录二进制的响应数据的输出流,此方法和getWriter()方法两者只能调用其一 Writer getWriter() 返回一个记录文本的响应数据的PrintWriter void reset 清除输出缓存及所有响应头标 void setContentLength(int Length) 设置响应的内容体的长度 void setContentType(String type) 设置响应的内容类型
4.分析Servlet接口及其实现类
1.HttpServlet类
- 1.Web应用大多都是通过HTTP协议和客户端进行交互,因此在Servlet接口中提供了一个抽象类
javax.servlet.http.HttpServlet
,它是GenericServlet
的子类,专门创建基于HTTP协议的Servlet- 2.HttpServlet源码分析
- 1.配置源码包:Eclipse–Window–Preferences–Java–Installed JRE
- 2.查看源码:Ctrl+鼠标左键点击要查看的类即可查看源码
- 3.手动配置源码包:如果通过步骤2无法查看源码,可通过网络下载相应的xxx_src.zip文件(无需解压),然后点击步骤2中的Attach Resouce手动配置
- 4.分析HttpServlet源码
public abstract class HttpServlet extends GenericServlet { ... ... protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_get_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } ... ... protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_post_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } ... ... protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { // Invalid date header - proceed as if none was set ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } } ... ... public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); } } ... ...
- 1.HttpServlet主要有两大功能:第一是根据用于请求方式的不同,定义相应的doXxx()方法处理用户请求;第二是通过service()方法将HTTP请求和相应分别强转为HttpServletRequest和HttpServletResponse类型的对象
- 2.HttpServlet在重写的service()方法中,为每一种Http请求方式都定义了对应的doXxx()方法;因此当定义的类继承HttpServlet后只需根据请求方式重写相应的doXxx()方法即可而不需要重写service()方法
- 3.编译的步骤
2.ServletConfig接口
- 1.Servlet运行期间需要一些辅助信息(例:文件使用的编码等),这些信息可以在web.xml文件中使用一个或多个
< init-param>
元素进行配置- 2.当Tomcat初始化一个Servlet时,会将该Servlet的配置信息封装到一个ServletConfig对象中
- 3.通过调用init(ServletConfig config)方法将ServletConfig对象传递给Servlet
- 4.ServletConfig定义了一系列获取配置信息的方法(即通过ServletConfig对象可以获得web.xml文件中的参数信息)
方法说明 功能描述 String getInitParameter(String name) 根据初始化参数名返回对应的初始化参数值 Enumeration getInitParameterNames() 返回一个Enumeration对象,其中包含了所有的初始化参数名 ServletContext getServletContext() 返回一个代表当前Web应用的ServletContext对象 String getServletName() 返回一个Servlet的名字,即web.xml中< servlet-name>元素的值 <servlet> <servlet-name>test1</servlet-name> <servlet-class>test.ServletTest1</servlet-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>test1</servlet-name> <url-pattern>/test/*</url-pattern> </servlet-mapping>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); ServletConfig config = this.getServletConfig(); String paramValue = config.getInitParameter("encoding"); String ServletName = config.getServletName(); out.println("ServletTest1<br/>"); out.println("<h3>" + paramValue + "</h3>"); out.println(ServletName); }
- 语法说明:
- 1.< init-param>元素:表示要设置的参数
- 2.< param-name>元素:表示参数的名称
- 3.< param-value>元素:表示参数的值
- 4.注意doGet()的方法中需要设置响应的格式为html文档,否则不会显示格式
3.ServletContext接口
- 1.当Servlet容器启动时会为每个Web应用创建一个唯一的ServletContext对象代表当前的Web应用
- 2.ServletContext接口可以获取Web应用程序的初始化参数
- 1.在web.xml文件中,不仅可以配置某个Servlet的初始化信息,还可以配置整个Web应用的初始化信息,Web应用初始化参数配置方法如下
<context-param> <param-name>xxx</param-name> <param-value>yyy</param-name> </context-param>
- 2.
< context-param>
元素位于根元素< web-app>中,它的子元素< param-name>
和< param-value>
分别用来指定参数的名字和参数值- 3.想要使用这些参数信息可以使用ServletContext接口,通过该接口给出的方法获得
<context-param> <param-name>SchoolName</param-name> <param-value>huazhong</param-value> </context-param>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); ServletConfig config = this.getServletConfig(); ServletContext context1 = this.getServletContext(); ServletContext context2 = config.getServletContext(); String paramValue = config.getInitParameter("encoding"); String ServletName = config.getServletName(); Enumeration<String> paramValue1 = context1.getInitParameterNames(); while(paramValue1.hasMoreElements()) { String name = paramValue1.nextElement(); String value = context1.getInitParameter(name); out.println("<h3>" + name + ":" + value + "</h3>"); } Enumeration<String> paramValue2 = context2.getInitParameterNames(); while(paramValue2.hasMoreElements()) { String name = paramValue2.nextElement(); String value = context2.getInitParameter(name); out.println("<h3>" + name + ":" + value + "</h3>"); } out.println("ServletTest1<br/>"); out.println("<h3>" + paramValue + "</h3>"); out.println(ServletName); }
- 语法说明:
- 1.结果1和结果2的区别:web.xml中ServletTest1配置了信息,而ServletTest2没有配置信息,所以ServletTest2中paramValue为null,ServletName为包名.类名
- 2.context参数信息是整个Web应用的初始信息,所有两个Servlet都可以获取
- 3.实现多个Servlet对象共享数据
- 1.由于一个Web应用中的所有Servlet共享同一个ServletContext对象,因此,ServletContext对象的域属性可以被该Web应用中的所有Servlet访问
- 2.ServletContext接口的方法
方法说明 功能描述 Enumeration getAttributeNames() 返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的所有域属性名 Object getAttribute(String name) 根据参数指定的属性名返回一个与之匹配的域属性值 void removeAttribute(String name) 根据参数指定的域属性名,从ServletContext中删除匹配的域属性 void setAttribute(String name,Object obj) 设置ServletContext的域属性,其中name是域属性名,obj是域属性值 - ServletTest1
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = this.getServletContext(); context.setAttribute("data", "this is ServletTest1's data"); }
- ServletTest2
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); ServletContext context = this.getServletContext(); String value = (String) context.getAttribute("data"); out.println(value); }
- 语法说明:
- 1.context.getAttribute(String name)方法返回的是Object对象,需要强转为String类型
- 2.需要先运行ServletTest1再运行ServletTest2才会成功显示,否则显示为null
- 3.ServletContext对象所存储的数据可以被多个Servlet所共享
- 4.读取Web应用下的资源文件
- 1.实际开发中可能会读取Web应用中的一些资源文件(例:配置文件,图片等),为此在ServletContext接口中定义了一些读取Web资源的方法,这些方法是依靠Servlet容器来实现的
- 2.Servlet容器根据资源文件相对于Web应用的路径,返回关联资源文件的IO流,资源文件在文件系统的绝对路径等
- 3.ServetContext接口的常用方法
方法说明 功能描述 Set getResourcePaths(String path) 返回一个Set集合,集合中包含资源目录中子目录的和文件的路径名称;参数path必须以正斜线 /
开始,指定匹配资源的部分路径String getRealPath(String path) 返回资源文件在服务器文件系统上的真实路径(文件的绝对路径);参数path代表资源文件的虚拟路径,它以正斜线 /
开始,/
表示当前Web应用的根目录,如果Servlet容器不能将虚拟路径转换为文件系统的真实路径,则返回nullURL getResource(String path) 返回映射到某个资源文件的URL对象;参数path必须以正斜线 /
开始InputStream getResourceAsStream(Path path) 返回映射到某个资源文件的InputStream输入流对象;参数path传递规则和getResource()方法一致 - 1.创建一个资源文件(注意文件是在src/main/java中创建)
- 2.编写资源文件内容
School = qhUniversity Address = Beijing
- 3.创建读取资源文件的Servlet(两种方式)
//方法一 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); ServletContext context = this.getServletContext(); PrintWriter out = response.getWriter(); InputStream in = context.getResourceAsStream("/WEB-INF/classes/nyst.properties"); Properties pros = new Properties(); pros.load(in); out.println("School:" + pros.getProperty("School") + "<br/>"); out.println("Address:" + pros.getProperty("Address") + "<br/>"); }
//方法二 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); ServletContext context = this.getServletContext(); PrintWriter out = response.getWriter(); String path = context.getRealPath("/WEB-INF/classes/test.properties"); FileInputStream in = new FileInputStream(path); Properties pros = new Properties(); pros.load(in); out.println(path+"<br/>"); out.println("School:" + pros.getProperty("School") + "<br/>"); out.println("Address:" + pros.getProperty("Address") + "<br/>"); }
- 语法说明:
- 1.资源文件后缀名一般是
.properties
- 2.注意文件是在src/main/java中创建,创建后会自动复制到Tomcat相应项目的WEB-INF/classes目录下(资源文件在Tomcat服务器相应项目的WEB-INF/classes目录下才能正常运行)
- 3.getResourceAsStream(String path)方法获得关联nyst.properties资源文件的输入流对象;其中的path必须以正斜线/开始,表示nyst.properties文件相对于Web应用的相对路径
- 4.可以通过使用getRealPath(String path)方法获取资源文件的绝对路径;
- 5.注意两者的区别:
- 一个是
InputStream in = context.getResourceAsStream("/WEB-INF/classes/nyst.properties");
- 一个是
String path = context.getRealPath("/WEB-INF/classes/test.properties");FileInputStream in = new FileInputStream(path);
4.HttpServletRequest接口
- HttpServletRequest接口继承自ServletRequest接口,专门用来封装HTTP请求信息
- HTTP请求信息分为请求行,请求头,请求消息体3部分
1.获取请求行信息的相关方法
- 访问Servlet时会在请求信息的请求行中包含:请求方法,请求资源名,请求路径等信息
- HttpServletRequest接口中定义了一系列用于获取请求行信息的方法
方法声明 功能描述 String getMethod 该方法用于获取HTTP请求信息中的请求方式(例:GET,POST等) String getRequestURI() 该方法用于获取请求行中的资源名称(即位于URL的主机和端口之后,参数之前的部分) String getQueryString() 该方法用于获取请求行中的参数(即资源路径?后面的所有内容) String getProtocol() 该方法用于获取请求行中的协议名和版本(例:HTTP/1.0) String getContextPath() 该方法用于获取请求URL中属于Web应用的路径,该路径以/开头,表示相对于整个Web站点的根目录,且路径结尾不含/,如果请求URL属于Web站点的根目录,那么返回结果为空字符串("") String getServletPath() 该方法用于获取Servlet的名称(未配置xml)或Servlet所映射的路径(已配置xml) String getRemoteAddr() 该方法用于获取请求客户端的IP地址,其格式类似于"192.168.0.1" String getRemoteHost() 该方法用于获取请求客户端的完整主机名,其格式类似于"pc1.nyst.cn"(如果无法解析出客户端的完整主机名,该方法将会返回客户端的IP地址) int getRemotePort() 该方法用于获取请求客户端网络连接的端口号 String getLocalAddr() 该方法用于获取Web服务器上接收当前请求网络连接的IP地址 String getLocalName() 该方法用于获取Web服务器上接收当前网络连接IP所对应的主机名 int getLocalPort() 该方法用于获取Web服务器上接收当前网络连接的端口号 String getServletName() 该方法用于获取当前请求所指向的主机名(即HTTP请求消息中Host头字段所对应的主机名部分) int getServletPort() 该方法用于获取当前请求所连接的服务器端口号(即HTTP请求消息中Host头字段所对应的端口号部分) String getScheme) 该方法用于获取请求的协议名(例:http,https,ftp) StringBuffer getRequestURL() 该方法用于获取客户端发出请求时的完整URL(包括协议,服务器名,端口号,资源路径等信息),但不包括后面的参数部分(该方法返回的结果是StringBuffer类型而不是String类型,便于对结果进行修改) - RequestLine.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录请求页面</title> </head> <body> <form action="RequestLineServlet"> 用户名:<input type="text" name="username"><br/> 密 码:<input type="password" name="pwd"><br/> <input type="submit" name="submit" value="提交"> </form> </body> </html>
- RequestLineServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("getMethod: " + "<b>" + request.getMethod() + "</b>" + "<br>"); out.println("getRequestRUI: " + "<b>" + request.getRequestURI() + "</b>" + "<br>"); out.println("getQueryString: " + "<b>" + request.getQueryString() + "</b>" + "<br>"); out.println("getMethod: " + "<b>" + request.getMethod() + "</b>" + "<br>"); out.println("getProtocol: " + "<b>" + request.getProtocol() + "</b>" + "<br>"); out.println("getContextPath: " + "<b>" + request.getContextPath() + "</b>" + "<br>"); out.println("getPathInfo: " + "<b>" + request.getPathInfo() + "</b>" + "<br>"); out.println("getPathTranslated: " + "<b>" + request.getPathTranslated() + "</b>" + "<br>"); out.println("getServletPath: " + "<b>" + request.getServletPath() + "</b>" + "<br>"); out.println("getRemoteAddr: " + "<b>" + request.getRemoteAddr() + "</b>" + "<br>"); out.println("getRemoteHost: " + "<b>" + request.getRemoteHost() + "</b>" + "<br>"); out.println("getRemotePort: " + "<b>" + request.getRemotePort() + "</b>" + "<br>"); out.println("getLocalAddr: " + "<b>" + request.getLocalAddr() + "</b>" + "<br>"); out.println("getLocalName: " + "<b>" + request.getLocalName() + "</b>" + "<br>"); out.println("getLocalPort: " + "<b>" + request.getLocalPort() + "</b>" + "<br>"); out.println("getServerName: " + "<b>" + request.getServerName() + "</b>" + "<br>"); out.println("getServerPort: " + "<b>" + request.getServerPort() + "</b>" + "<br>"); out.println("getScheme: " + "<b>" + request.getScheme() + "</b>" + "<br>"); out.println("getRequestURL: " + "<b>" + request.getRequestURL() + "</b>" + "<br>"); }
- RequestLineServlet的xml配置文件
<servlet> <servlet-name>RequestLineServlet</servlet-name> <servlet-class>servletDemo.RequestLineServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>RequestLineServlet</servlet-name> <url-pattern>/RequestLine</url-pattern> </servlet-mapping>
- 语法说明:
- 1.编写jsp文件,注意jsp文件的action为xml中
<url-pattern>
元素对应的内容;如果没有配置xml文件,则action为servlet的名称- 2.编写servlet文件,注意设置字符编码格式
- 3.编写web.xml文件,注意
<url-pattern>
元素是servlet对外访问路径2.获取请求消息头的相关方法
- 当请求Servlet时,需要通过请求头向服务器传递附加信息,例:客户端可以接收的数据类型,压缩方式,语言等
- 为此在HttpServletRequest接口中定义了一系列用于获取HTTP请求头字段的方法
方法声明 功能描述 String getHeader(String name) 该方法用于获取一个指定头字段的值;如果请求消息中没有包含指定的头字段,getHeader()方法返回null;如果请求消息中包含多个指定名称的头字段,getHeader()方法返回其中第一个头字段的值 Enumeration getHeaders(String name) 该方法返回一个Enumeration集合对象,该集合对象由请求消息中出现的某个指定名称的所有头字段值组成,在多数情况下一个头字段名在请求消息中只出现一次,但有时候可能会出现多次 Enumeration getHeaderNames() 该方法用于获取一个包含所有请求头字段的Enumeration对象 int getIntHeader(String name) 该方法用于获取指定名称的头字段,并将其值转为int类型。注意如果指定名称的头字段不存在,返回值为-1;如果获取到的头字段的值不能转为int类型,将发生NumberFormatException异常 long getDateHeader(String name) 该方法用于获取指定头字段的值,并将其按GMT时间格式转换为一个代表日期/时间的长整数,这个长整数是自1970年1月1日0点0分0秒算起的以毫秒为单位的时间值 String getContentType() 该方法用于获取Content-Type头字段的值,结果为String类型 int getContentLength() 该方法用于获取Content-Length头字段的值,结果为int类型 String getCharacterEncoding() 该方法用于返回请求消息的实体部分的字符编码,通常是从Content-Type头字段中进行提取 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); Enumeration headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String headerName = (String) headerNames.nextElement(); out.println(headerName + ": " + "<b>" + request.getHeader(headerName) + "</b><br>"); } //异常 out.println("getIntHeader: " + request.getIntHeader("host") + "<br/>"); //异常 out.println("DateHeader: " + request.getDateHeader("host") + "<br/>"); out.println("ContentType: " + request.getContentType() + "<br/>"); out.println("ContentLength: " + request.getContentLength() + "<br/>"); out.println("CharacterEncoding: " + request.getCharacterEncoding() + "<br/>"); }
3.利用Referer请求防止盗链
- referer: 浏览器向服务器发出的请求,可能是直接在浏览器中输入URL地址,也可能是单击一个网页上的超链接;第一种直接在浏览器地址栏中输入URL,浏览器不会发送referer请求头;第二种单击一个网页上的超链接,浏览器会使用Referer头字段标识发出请求的超链接所在网页的URL
- 原理: 获取referer头字段的值,检查请求来源,判断其是否是本站链接发送的请求;如果是则允许访问,否则不允许访问
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); String referer = request.getHeader("referer"); String sitePart = "http://" + request.getServerName(); if(referer != null && referer.startsWith(sitePart)) { out.println(referer + "<br/>"); out.println(sitePart + "<br/>"); out.println("正在准备下载"); } else { RequestDispatcher rd = request.getRequestDispatcher("download.html"); rd.forward(request, response); } }
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <title>下载页面</title> </head> <body> <h4>请前往官方页面进行下载</h4> <a href="/MyselfWeb/Down">Download</a> </body> </html>
- 语法说明:
- 第一次请求Servlet时,请求消息中不含Referer请求头,所以Servlet将下载请求转发给了download页面
- 第二次请求Servlet时,请求消息中包含Referer请求头,并且其值与Servlet位于同一个站点,因此Servlet接受下载请求
- 注意最好使用jsp,使用html时会出现乱码
4.获取参数
- 实际开发中经常需要获取用户提交的表单数据(例:用户名,密码等),为了方便获取表单中的请求参数,在HttpServletRequest接口的父类ServletRequest中,定义了一系列获取请求参数的方法
方法声明 功能描述 String getParameter(String name) 该方法用于获取某个指定名称的参数值;如果请求消息中没有包含指定名称的参数,则返回null;如果指定名称的参数存在但没有设置值,则返回一个空串;如果请求消息中包含有多个该指定名称的参数,则返回第一个出现的参数值 String[] getParameterValues(String name) HTTP请求中可以有多个相同名称的参数(通常由一个包含有多个同名的字段元素的Form表单生成);如果要获得HTTP请求消息中的同一个参数名所对应的所有参数值,需要使用该方法 Enumeration getParameterNames() 该方法用于返回一个包含请求消息中所有参数名的Enumeration对象,在此基础上可以对请求消息中的所有参数进行遍历 Map getParameterMap() 该方法用于将请求消息中的所有参数名和值装入一个Map对象中返回 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); username = new String(username.getBytes("ISO-8859-1"),"UTF-8"); password = new String(password.getBytes("ISO-8859-1"),"UTF-8"); out.println("用户名: " + username + "<br/>"); out.println("密码: " + password + "<br/>"); String[] hobby = request.getParameterValues("hobby"); out.println("爱好:" + "<br/>"); for(int i=0; i<hobby.length; i++) { out.println(hobby[i] + " "); } out.println("<hr/>"); Enumeration Parameters = request.getParameterNames(); while(Parameters.hasMoreElements()) { String param = (String) Parameters.nextElement(); out.println(param + "<br/>"); } String csd = Charset.defaultCharset().name(); out.println("get方法使用的码表是:" + csd); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); out.println("用户名: " + username + "<br/>"); out.println("密码: " + password + "<br/>"); String[] hobby = request.getParameterValues("hobby"); out.println("爱好:" + "<br/>"); for(int i=0; i<hobby.length; i++) { out.println(hobby[i] + " "); } out.println("<hr/>"); Enumeration Parameters = request.getParameterNames(); while(Parameters.hasMoreElements()) { String param = (String) Parameters.nextElement(); out.println(param + "<br/>"); } }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form action="FormTest" method="get"> <table> <tr> <td>用户名:</td><td><input type="text" name="username"></td> </tr> <tr> <td>密 码:</td><td><input type="password" name="password"></td> </tr> <tr> <td>爱 好:</td> <td> <input type="checkbox" name="hobby" value="football">足球 <input type="checkbox" name="hobby" value="basketball">篮球 <input type="checkbox" name="hobby" value="table tennis">乒乓球 </td> </tr> <tr> <td>性 别:</td> <td> <input type="radio" name="sex" value="boy">男 <input type="radio" name="sex" value="girl">女 </td> </tr> <tr> <td></td> <td> <input type="submit" name="submit" value="提交"> <input type="reset" name="reset" value="重置"> </td> </tr> </table> </form> </body> </html>
- 语法说明:
- 1.jsp页面中的action可以是< url-pattern>元素的值,也可以是Servlet的名称
5.传递参数
- Request对象不仅可以获取一系列数据,还可以通过属性传递数据
- 只有属于同一个请求中的数据才可以通过ServletReques对象传递数据
方法声明 功能描述 String setAttribute(String name,Object obj) 该方法用于将一个属性对象与一个名称关联后存储进ServletRequest对象中;如果ServletRequest对象中已经存在指定名称的属性,该方法将先删除原来的属性再添加新的属性;如果传递给该方法的属性值对象为null,则会删除指定名称的属性(等同于removeAttribute()方法) String getAttribute(String name) 该方法用于从ServletRequest对象中返回指定名称的属性对象 String removeAttribute(String name) 该方法用于从ServletRequest对象中删除指定名称的属性 Enumeration getAttributeNames() 该方法用于返回一个包含ServletRequest对象中所有属性名的Enumeration对象,在此基础上可以对ServletRequest对象中的所有属性进行遍历处理 6.解决请求参数中文乱码问题
- 1.乱码产生的原因:
- 由于HTML设置了浏览器在传递参数时,采用的编码方式是UTF-8,但在解码时采用的是默认的ISO-8859-1,因此会导致乱码的出现
- 1.POST方式解决乱码:
- 1.HttpServletRequest接口中,提供了一个
setCharacterEncoding()
方法,该方法用于设置request对象的解码方式- 2.这种解决乱码的方式只对Post方式有效,对Get方式无效
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form action="FormTest" method="post"> <table> <tr> <td>用户名:</td><td><input type="text" name="username"></td> </tr> <tr> <td>密 码:</td><td><input type="password" name="password"></td> </tr> <tr> <td>爱 好:</td> <td> <input type="checkbox" name="hobby" value="football">足球 <input type="checkbox" name="hobby" value="basketball">篮球 <input type="checkbox" name="hobby" value="table tennis">乒乓球 </td> </tr> <tr> <td>性 别:</td> <td> <input type="radio" name="sex" value="boy">男 <input type="radio" name="sex" value="girl">女 </td> </tr> <tr> <td></td> <td> <input type="submit" name="submit" value="提交"> <input type="reset" name="reset" value="重置"> </td> </tr> </table> </form> </body> </html>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); out.println("用户名: " + username + "<br/>"); out.println("密码: " + password + "<br/>"); String[] hobby = request.getParameterValues("hobby"); out.println("爱好:" + "<br/>"); for(int i=0; i<hobby.length; i++) { out.println(hobby[i] + " "); } out.println("<hr/>"); Enumeration Parameters = request.getParameterNames(); while(Parameters.hasMoreElements()) { String param = (String) Parameters.nextElement(); out.println(param + "<br/>"); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request,response); }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form action="FormTest" method="get"> <table> <tr> <td>用户名:</td><td><input type="text" name="username"></td> </tr> <tr> <td>密 码:</td><td><input type="password" name="password"></td> </tr> <tr> <td>爱 好:</td> <td> <input type="checkbox" name="hobby" value="football">足球 <input type="checkbox" name="hobby" value="basketball">篮球 <input type="checkbox" name="hobby" value="table tennis">乒乓球 </td> </tr> <tr> <td>性 别:</td> <td> <input type="radio" name="sex" value="boy">男 <input type="radio" name="sex" value="girl">女 </td> </tr> <tr> <td></td> <td> <input type="submit" name="submit" value="提交"> <input type="reset" name="reset" value="重置"> </td> </tr> </table> </form> </body> </html>
- 2.GET方式解决乱码
- 1.先使用错误码表ISO-8859-1将数据重新编码,然后再使用码表UTF-8进行解码(即:UTF-8编码–>ISO-8859-1解码–>ISO-8859-1编码–>UTF-8解码)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form action="FormTest" method="get"> <table> <tr> <td>用户名:</td><td><input type="text" name="username"></td> </tr> <tr> <td>密 码:</td><td><input type="password" name="password"></td> </tr> <tr> <td>爱 好:</td> <td> <input type="checkbox" name="hobby" value="football">足球 <input type="checkbox" name="hobby" value="basketball">篮球 <input type="checkbox" name="hobby" value="table tennis">乒乓球 </td> </tr> <tr> <td>性 别:</td> <td> <input type="radio" name="sex" value="boy">男 <input type="radio" name="sex" value="girl">女 </td> </tr> <tr> <td></td> <td> <input type="submit" name="submit" value="提交"> <input type="reset" name="reset" value="重置"> </td> </tr> </table> </form> </body> </html>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); username = new String(username.getBytes("ISO-8859-1"),"UTF-8"); password = new String(password.getBytes("ISO-8859-1"),"UTF-8"); out.println("用户名: " + username + "<br/>"); out.println("密码: " + password + "<br/>"); String[] hobby = request.getParameterValues("hobby"); out.println("爱好:" + "<br/>"); for(int i=0; i<hobby.length; i++) { out.println(hobby[i] + " "); } out.println("<hr/>"); Enumeration Parameters = request.getParameterNames(); while(Parameters.hasMoreElements()) { String param = (String) Parameters.nextElement(); out.println(param + "<br/>"); } }
5.HttpServletResponse接口
- 该接口继承自
ServletResponse接口
,专门用来封装HTTP响应信息- 由于HTTP响应消息分为状态行,响应消息头,消息体三部分,因此在HttpServletResponse接口中定义了向客户端发送响应状态码,响应消息头,响应消息体的方法
1.发送状态码相关的方法
- 1.setStatus(int status)方法
- 1.该方法用于设置HTTP响应消息的状态码并生成响应状态行
- 2.响应状态行中的状态描述信息直接与状态码有关,而HTTP版本由服务器确定,只要通过该方法设置了状态码即可实现状态行的发送
- 3.正常情况Web服务器会默认产生一个状态码为200的状态行
- 2.sendError(int sc)方法
- 1.该方法用于发送表示错误信息的状态码(例:404状态码表示找不到客户端请求的资源)
- 2.在response对象中,提供了两个重载的sendError(int sc)方法
public void sendError(int code) throws java.io.IOException public void sendError(int code,String ,message) throws java.io.IOException
2.发送响应消息头相关的方法
- 1.当Servlet向客户端发送响应消息时,HTTP协议的响应头字段有很多种
- 2.HttpServletResponse接口中定义了一系列设置HTTP响应头字段的方法
方法声明 功能描述 void addHeader(String name,String value) 该方法用来设置HTTP协议的响应头字段,其中参数name用于指定响应头字段的名称;参数value用于指定响应头字段的值;该方法可以增加同名的响应头字段 void setHeader(String name,String value) 该方法用来设置HTTP协议的响应头字段,其中参数name用于指定响应头字段的名称;参数value用于指定响应头字段的值;该方法会覆盖同名的响应头字段 void addIntHeader(String name,String value) 该方法用来设置包含整数值响应头字段,避免了使用上面两种方法时,需要将int类型的设置值转换为String类型的麻烦 void setIntHeader(String name,String value) 该方法用来设置包含整数值响应头字段,避免了使用上面两种方法时,需要将int类型的设置值转换为String类型的麻烦 void setContentLength(int len) 该方法用来设置响应消息的实体内容的大小,单位为字节,对于HTTP协议来说,这个方法就是设置Content-Length响应头字段的值 void setContentType(String type) 该方法用来设置Servlet输出内容的MIME类型,对于HTTP协议来说就是设置Content-Type响应头字段的值,(例:如果发送到客户端的内容是jpeg格式的图像数据,就需要将响应头字段的类型设置为image/jpeg;如果响应的内容为文本,该方法还可以设置字符编码(如:text/html;charset=utf-8)) void setLocale(Locale loc) 该方法用来设置响应消息的本地化信息,对于HTTP来说,就是设置Content-Language响应头字段和Content-Type头字段中的字符编码部分; 如果HTTP消息没有设置Content-Type头字段,该方法设置的字符集编码不会出现在HTTP消息的响应头中,如果调用了setCharacterEncoding()或setContentType()方法指定了相应内容的字符集编码,该方法将不再具有指定字符集编码的功能 void setCharacterEncoding(String charset) 该方法用来设置输出内容使用的字符编码,对于HTTP协议来说就是设置Content-Type头字段的字符集编码部分,如果没有设置Content-Type头字段,setCharacterEncoding方法设置的字符集编码不会出现在HTTP消息的响应头中;该方法比setContentType()和setLocale()方法的优先权高,它的设置结果将覆盖其他两种方法所设置的字符码表 3.发送响应消息体相关的方法
- HTTP响应消息中大量的数据都是通过响应消息体传递,ServletResponse遵循以IO流传递大量数据的设计理念
- 在发送响应消息体时,定义了两个与输出流相关的方法
- 1.getOutputStream()方法
- 该方法所获取的字节输出流对象为ServletOutputStream类型
- ServletOutputStream是OutputStream的子类,它可以直接输出字节数组中的二进制数据
- 2.getWriter()方法
- 该方法获取的字符输出流对象为PrintWriter类型
- PrintWriter类型的对象可以直接输出字符文本内容,想要输出内容为字符文本的网页文档可以使用该方法
- 虽然response对象的getOutputStream和getWriter()方法都可以发送响应消息体,但是它们互相排斥,不可同时使用,否则会发生错误
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub String data = "nyst"; OutputStream out = response.getOutputStream(); out.write(data.getBytes()); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub String data = "test"; PrintWriter out = response.getWriter(); out.println(data); }
4.解决中文输出乱码问题
1.由于计算机中的数据都是以二进制形式存储的,因此当传输文本时就会发生字符和字节之间的转换
2.字符和字节之间的转换是通过查码表完成的,将字符转换为字节的过程称为编码,将字节转换成字符的过程称为解码。 //如果编码和解码使用的码表不一致就会导致乱码问题
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub String data = "中国"; PrintWriter out = response.getWriter(); out.println(data); }
语法说明:
- 1.如图所示浏览器显示的内容是
??
,说明发生了乱码问题;此处产生乱码的原因是response对象的字符输出流在编码时,采用的是ISO-8859-1的字符码表;该码表不兼容中文,会将中国
编码为63 63
(在ISO-8859-1的码表中查不到的字符就会显示63)- 2.当浏览器对接收到的数据进行解码时,会采用默认的码表GB2312,将
63
解码为?
,因此浏览器将中国两个字符显示为??
3.HttpServletResponse接口中,提供了一个setCharacterEncoding()方法,该方法用于设置字符的编码方式
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub //设置字符编码使用的码表为UTF-8 response.setCharacterEncoding("utf-8"); String data = "中国"; PrintWriter out = response.getWriter(); out.println(data); }
语法说明:
- 1.如图所示浏览器显示的还是乱码,这是由于浏览器解码错误,因为response对象的字符输出流设置的编码方式为UTF-8,而浏览器使用的解码方式是GB2312
4.在HttpServletResponse对象中,提供了两种解决乱码的方案
- 第一种方式
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub //使用utf-8编码 response.setCharacterEncoding("utf-8"); //通知浏览器使用utf-8编码 response.setHeader("Content-Type", "text/html;charset=utf-8"); String data = "中国"; PrintWriter out = response.getWriter(); out.println(data); }
- 第二种方式
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); String data = "中国"; PrintWriter out = response.getWriter(); out.println(data); }
5.实现网页定时刷新并跳转
- 1.HTTP协议中定义了一个Refresh头字段,它可以通知浏览器再指定的时间内自动刷新,并可以添加跳转功能
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setHeader("Refresh", "3"); response.getWriter().println(new java.util.Date()); }
- 2.网页自动刷新并跳转
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); String data = "中国"; PrintWriter out = response.getWriter(); out.println(data); response.setHeader("Refresh", "2;URL=http://www.baidu.com"); }
6.实现请求重定向
- 某些情况下针对客户端的请求,一个Servlet类可能无法完成全部工作,这时可以使用请求重定向来完成
- 注意通过请求重定向处理客户端请求会改变浏览器的URL地址
- 请求重定向:指Web服务器接收到客户端的请求后,可能由于某些条件限制,不能访问当前请求URL所指向的Web资源而是指定了一个新的资源路径,让客户端重新发送请求
- 为了实现请求重定向,在HttpServletResponse接口中,定义了一个sendRedirect()方法,该方法用于生成302响应码和Location响应头,从而通知客户端重新访问Location响应头中指定的URL
- 语法格式:
public void sendRedirect(java.lang.String location) throws java.io.IOException
- 语法说明:
- 参数location可以使用相对URL,Web服务器会自动将相对URL翻译成绝对URL,再生成Location头字段
- Login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form action="LoginServlet" method="get"> <table> <tr> <td>用户名:</td><td><input type="text" name="username"></td> </tr> <tr> <td>密 码:</td><td><input type="password" name="password"></td> </tr> <tr> <td></td> <td> <input type="submit" name="submit" value="登录"> <input type="reset" name="reset" value="取消"> </td> </tr> </table> </form> </body> </html>
- LoginServlet.java
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); if(username==null) { username=""; } if(password==null) { password=""; } if(username.equals("wu") && password.equals("123456")) { response.sendRedirect("success.html"); }else { response.sendRedirect("Login.jsp"); } }
- success.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录成功</title> </head> <body> <h3>欢迎</h3> </body> </html>
6.RequestDispatcher接口
- 1.当一个Web资源收到客户端的请求后,如果希望服务器通知另一个资源去处理请求,除了使用sendRedirect方法实现请求重定向外,还可以通过RequestDispatcher接口的实例对象实现
- 2.ServletRequest接口中定义了一个获取RequestDispatcher对象的方法
- 3.获取到RequestDispatcher对象后,可以使用该对象中的两个方法通知其他Web资源处理当前的Servlet请求
方法声明 功能描述 RequestDispatcher getRequestDispatcher(String path) 该方法返回封装了某个路径所指定资源的RequestDispatcher对象,其中参数path必须以/开头,用于表示当前Web应用的根目录 forward(ServletRequest request,ServletResponse response) 该方法用于将请求从一个Servlet传递给另一个Web资源。在Servlet中,可以对请求做一个初步处理,然后通过调用这个方法,将请求传递给其他资源进行响应;注意:该方法必须在响应提交给客户端之前被调用,否则将抛出IIIegalStateException异常 include(ServletRequest request,ServletResponse response) 该方法用于将其他的资源作为当前响应内容包含进来 - 4.forword方法可以实现请求转发,include方法可以实现请求包含
1.请求转发
- 1.Servlet中如果当前Web资源不想处理请求时,可以通过forward()方法将当前请求传递给其他的Web资源进行处理,这种方式称为请求转发
- 2.原理:当浏览器客户端访问Servlet1时,可以通过forward()方法将请求转发给其他Web资源,其他Web资源处理完请求后,直接将响应结果返回到客户端
- 3.注意:forward转发后的Servlet2页面的地址栏仍然是浏览器对Servlet1的请求路径,但是浏览器中内容是Servlet2页面,这是因为请求转发是发生在服务器内部的行为,从Servlet1到到Servlet2属于一次请求,在一次请求中可以使用request属性进行数据共享
- RequestForwardServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); request.setAttribute("school", "河南大学"); PrintWriter out = response.getWriter(); out.println("测试"); RequestDispatcher rd = request.getRequestDispatcher("/RequestForward"); rd.forward(request, response); }
- RequestForward.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); String school = (String) request.getAttribute("school"); out.println(school + "欢迎登录<br/>Forward响应成功"); }
- 语法说明:
- 如图所示显示的内容是RequestForward页面,URL路径仍为RequestForwardServlet
2.请求包含
- 1.请求包含:指使用include()方法将Servlet请求转发给其他Web资源进行处理
- 2.与请求转发不同的是:在请求包含返回的响应消息中,既包含了当前Servlet的响应消息也包含了其他Web资源所作出的响应信息
- 3.原理:当客户端访问Servlet1时,Servlet1通过调用include()方法将其他Web资源包含进来,当请求处理完毕后回送给客户端的响应结果既包含当前Servlet的响应结果也包含其他Web资源的响应结果
- IncludeServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setAttribute("school", "东南大学"); PrintWriter out = response.getWriter(); out.println("清华大学"); RequestDispatcher rd = request.getRequestDispatcher("/Include"); rd.include(request, response); }
- Include.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); String school = (String) request.getAttribute("school"); out.println(school + "欢迎登录"); }
- IncludeServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); request.setAttribute("school", "东南大学"); PrintWriter out = response.getWriter(); out.println("清华大学"); RequestDispatcher rd = request.getRequestDispatcher("/Include"); rd.include(request, response); }
- Include.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub PrintWriter out = response.getWriter(); String school = (String) request.getAttribute("school"); out.println(school + "欢迎登录"); }
- 语法说明:
- 1.如图所示第一种情况会出现乱码,说明在Include中设置响应字符编码没有起作用
- 2.这次因为浏览器请求IncludeServlet时,用于封装响应消息的HttpServletResponse对象已经建立,该对象在编码时采用的是默认的ISO-8859-1,所以当客户端接收到数据时,Web服务器会继续保持调用HttpServletResponse对象中的信息,并采用GB2312解码从而导致乱码
- 3.使用include()方法实现请求包含后,浏览器显示的URL地址是不会发生变化的
5.Servlet的文件配置
- web.xml文件中< servlet-mapping>元素用于映射一个Servlet的对外访问路径,该路径也称虚拟路径
- 创建好的Servlet只有映射成虚拟路径,客户端才能对其进行访问
- 1.Servlet多重映射
- 指的是同一个Servlet可以被映射成多个虚拟路径(即:客户端可以通过多个虚拟路径实现对同一个Servlet的访问)
- 2.Servlet多重映射的实现方式
- ServletDemo1.java
package servletDemo; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class ServletDemo1 */ @WebServlet("/ServletDemo1") public class ServletDemo1 extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public ServletDemo1() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub PrintWriter out = response.getWriter(); out.println("<html><body><h3>Welcome To The First Servlet!</h3></body></html>"); out.flush(); } }
- 1.配置多个< servlet-mapping>元素
<servlet> <servlet-name>Demo1</servlet-name> <servlet-class>servletDemo.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>Demo1</servlet-name> <url-pattern>/test1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Demo1</servlet-name> <url-pattern>/test2</url-pattern> </servlet-mapping>
- 2.< servlet-mapping>元素下配置多个< url-pattern>子元素
<servlet> <servlet-name>Demo1</servlet-name> <servlet-class>servletDemo.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>Demo1</servlet-name> <url-pattern>/test1</url-pattern> <url-pattern>/test2</url-pattern> </servlet-mapping>
- 3.Servlet映射路径中的通配符
- 1.格式为
*.扩展名
(例:* .do
表示以.do结尾的URL请求路径可以访问该Serlvet;*
表示任何URL路径都可以访问该Servlet)- 2.格式为
/*
(例:/abc/ *
表示以abc开始的URL请求路径都可以访问该Servlet)- 4.注意
- 1.两种通配符的格式不能混合使用(例:
/abc/*do
是不合法的映射路径)- 2.客户端访问Servlet时,如果请求的URL地址能够匹配多个虚拟路径,Tomcat将采取最具体匹配原则查找与请求URL最接近的虚拟映射路径
- 5.最具体匹配原则
<servlet> <servlet-name>test1</servlet-name> <servlet-class>test.ServletTest1</servlet-class> </servlet> <servlet-mapping> <servlet-name>test1</servlet-name> <url-pattern>/test/*</url-pattern> </servlet-mapping> <servlet> <servlet-name>test2</servlet-name> <servlet-class>test.ServletTest2</servlet-class> </servlet> <servlet-mapping> <servlet-name>test2</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <servlet> <servlet-name>test3</servlet-name> <servlet-class>test.ServletTest3</servlet-class> </servlet> <servlet-mapping> <servlet-name>test3</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping> <servlet> <servlet-name>test4</servlet-name> <servlet-class>test.ServletTest4</servlet-class> </servlet> <servlet-mapping> <servlet-name>test4</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
- 说明:
- 1.
/test/*
:表示以/test/
开头的请求URL可以匹配到该Servlet- 2.
/*
:表示所有
请求URL都可以匹配到该路径- 3.
/test
:表示请求URL为/test
匹配到该Servlet- 4.
*.do
:表示以.do
结尾的请求URL可以匹配到该Servlet- 注意优先级:1和3的优先级比2高,2的优先级比4高;即:当有以
/
开始的具体URL时会优先选择该Servlet,如果都没有则会匹配/*
对应的Servlet;如果想使用*.do
则需要将/*
删除- 匹配优先级与配置在xml的顺序无关,只与上述说明有关
- 6.缺省Servlet
- 如果某个Servlet的映射路径仅仅是一个正斜线
/
,那么这个Servlet就是当前Web应用的缺省Servlet- Servlet’服务器在接收到访问请求时,如果在web.xml文件中找不到匹配的< servlet-mapping>元素的URL,就会将访问请求交给缺省Servlet处理(即:缺省Servlet用户处理其他Servlet都不处理的访问请求)
<servlet> <servlet-name>ServletTest5</servlet-name> <servlet-class>test.ServletTest5</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletTest5</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
- Tomca安装目录下的web.xml文件也配置了一个缺省Servlet
- org.apache.catalina.servlets.DefaultServlet被设置为缺省的Servlet
- 它对Tomcat服务器上所有Web应用都起作用
- 当Tomcat服务器中的某个Web应用没有缺省Servlet时,都会将DefaultServlet作为默认缺省的Servlet
- 当客户端访问Tomcat服务器中的某个静态HTML时,DefaultServlet会判断HTML是否存在,如果存在,就会将数据以流的形式回送给客户端,否则会报告404错误
1.Servlet别名形式的URL调用
- 在Tomcat服务器下,Servlet应该放到应用程序的WEB-INF\classes目录下,而调用Servlet的URL是
http://主机名/应用程序文件夹名/Servlet名
。同时大多数Web服务器还允许定义Servlet的别名,因此Servlet也可能以使用别名形式的URL调用- 1.部署Servlet
- 将ServletDemo1.java编译成ServletDemo1.class文件,然后将应用程序文件夹下的WEB-INF文件夹直接复制到webapps中的新建文件夹chap01中
- 修改前目录
- 修改后目录
- 2.修改web.xml文件
- 修改前
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>MyselfWeb</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> </web-app>
- 修改后
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>MyselfWeb</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- JSPC servlet mapping start --> <!-- 完成对Servlet的名称(name)和Servlet类(class)之间的匹配 --> <!-- 本例将名称为Demo1的Servlet匹配到servletDemo包中的ServletDemo1类--> <servlet> <servlet-name>Demo1</servlet-name> <display-name>Demo1</display-name> <description>The First Servlet</description> <servlet-class>servletDemo.ServletDemo1</servlet-class> </servlet> <!-- 完成了Servlet的映射,即如果在浏览器地址栏中出现了/Demo1的内容,则映射成名称为Demo1的Servlet --> <servlet-mapping> <servlet-name>Demo1</servlet-name> <url-pattern>/Demo1</url-pattern> </servlet-mapping> <!-- JSPC servlet mapping end --> </web-app>
- 修改前路径
- 修改后路径
6.会话及其会话技术
- 1.Web开发中,服务器跟踪用户信息的技术称为会话技术
- 2.Web会话过程:它指一个客户端与Web服务器之间连续发生的一系列请求和响应过程
- 3.HttpServletRequest和ServletContext都可以对数据进行保存,两者的区别:
- 1.HtttpServletRequest: 客户端请求Web服务器时,针对每次HTTP请求,Web服务器都会创建一个HttpServletRequest对象,该对象只能保存本次请求所传递的数据
- 2.ServletContext: 同一个Web应用共享同一个Servlet对象,所以同一个Web应用下的所有Servlet都能读取ServletContext保存的数据
1.Cookie对象
- 1.Cookie是一种会话技术,它用于将会话过程中的数据保存到用户的浏览器中,从而使浏览器和服务器可以更好的进行数据交互
- 2.Web应用中,当通过浏览器访问Web服务器时,服务器会给客户端发送一些信息,这些信息都保存在Cookie中
- 3.当浏览器再次访问服务器时,都会在请求头中将Cookie发送给服务器,方便服务器对浏览器作出正确的响应
- 4.服务器向客户端发送Cookie时,会在HTTP响应头字段中增加Set-Cookie响应头字段
- 5.流程说明:
- 1.当用户第一次访问服务器时,服务器会在响应消息中增加Set-Cookie头字段,将用户信息以Cookie的形式发送给浏览器
- 2.一旦用户浏览器接受了服务器发送的Cookie信息,就会将他保存在浏览器的缓存区中
- 3.当浏览器后续访问该服务器时,都会在请求消息中将用户信息以Cookie的形式发送给Web服务器,从而使服务器分辨出当前请求是哪个用户发出
- 6.Set-Cookie头字段中设置Cookie遵循一定的语法格式
Set-Cookie:user=nyst; path=/;
- 语法说明:
- 1.user:表示Cookie的名称;nyst:表示Cookie的值;path表示Cookie的路径属性
- 2.Cookie必须以键值对的形式存在,其属性可以有多个,但这些属性必须用分号和空格分隔
- 7.Cookie API
- Servlet API中提供了javax.servlet.http.Cookie类,该类包含生成Cookie信息和提取Cookie’信息各个属性的方法
方法声明 功能描述 public Cookie(String name,String value) 该方法为构造方法,参数name用于指定Cookie名称,Value用于指定Cookie的值;注意:Cookie一旦创建,名称name就不能修改,Cookie的值可以为任何值并且创建后可以被修改 String getName() 该方法用于返回Cookie的名称 void setValue(String newValue) 该方法用于为Cookie设置一个新的值 String getValue() 该方法用于返回Cookie的值 void setMaxAge(int expiry) 该方法用于设置Cookie在浏览器客户端上保持有效的秒数;如果设置的值为正整数,浏览器会将Cookie信息保存在本地硬盘中,从当前时间开始,在没有超过指定的秒数之前,这个Cookie都保持有效,并且同一台计算机上运行的浏览器都可以使用这个Cookie信息;如果设置的值为负整数,浏览器会将Cookie信息保存在缓存中,当浏览器关闭时,Cookie信息会被删除;如果设置值为0,则表示通知浏览器立即删除这个Cookie信息;默认情况该属性的值是-1 int getMaxAge() 该方法用于返回Cookie在浏览器客户端上保持有效的秒数 void setPath(String url) 该方法用于设置该Cookie项的有效目录路径;如果创建的某个Cookie对象没有设置Path属性,那么该Cookie只对当前访问路径所属的目录及其子目录有效;如果想让某个Cookie项对站点的所有目录下的访问路径都有效,应调用Cookie对象的setPath()方法将其Path属性设置为 /
String getPath() 该方法用于返回该Cookie项的有效目录路径 void setDomain(String pattern) 该方法用于设置该Cookie项的有效域;domain属性用来指定浏览器访问的域(例:百度的域为 baidu.com
);当设置domain属性时,必须以.
开头(例:domain=.baidu.com);默认情况domain属性的值为当前主机名,浏览器再访问当前主机下的资源时都会将Cookie信息回送给服务器;domain属性的值不区分大小写String getDomain() 该方法用于返回该Cookie项的有效域 void setVersion(int v) 该方法用于设置该Cooki项采用的协议版本 int getVersion() 该方法用于返回该Cooki项采用的协议版本 void setComment(String purpose) 该方法用于设置该Cookie项的注解部分 String getComment() 该方法用于返回该Cookie项的注解部分 void setSecure(boolean flag) 该方法用于设置该Cookie项是否值能使用安全的协议传送 String getSecure(() 该方法用于返回该Cookie项是否只能使用安全的协议传送 - 8.显示用户上次访问时间
- LastAccessServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=utf-8"); PrintWriter out =response.getWriter(); String lastAccessServlet = null; Cookie[] cookies = request.getCookies(); for(int i=0; cookies!=null&&i<cookies.length; i++) { if("lastAccess".equals(cookies[i].getName())) { lastAccessServlet = cookies[i].getValue(); break; } } if(lastAccessServlet == null) { out.println("您是首次访问本站!"); } else { out.println("您上次访问的时间是: " + lastAccessServlet); } String currentTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()); Cookie cookie = new Cookie("lastAccess",currentTime); response.addCookie(cookie); }
- 语法说明:
- 1.如图所示:开始显示的是图一,刷新后会显示上次访问的时间,每次刷新,时间都会改变
- 2.关闭浏览器后再打开浏览器,再次访问该Servlet显示的是图三而没有显示上次访问时间,这是因为在默认情况下,Cookie对象的Max-Age属性的值是-1,即:浏览器关闭时,删除该Cookie对象
- 3.可以通过setMaxAge()方法设置有效时间,只要Cookie设置的有效时间没有结束,用户就可以一直访问该Cookie保存的信息
2.Session对象
- 1.Cookie技术可以将用户的信息保存在各自的浏览器中,并且可以在多次请求下实现数据的共享
- 2.Session是一种将会话数据保存到服务器端的技术
- 3.原理: 当浏览器访问Web服务器时,Servlet容器就会为客户端创建一个Session对象和ID属性;当客户端后续访问服务器时,只要将ID标识号传递给服务器,服务器就能判断出该请求是哪个客户端发送的,从而选择与之对应的Session对象为其服务
- 1.如图所示:用户甲和用户乙都调用buyServlet将商品添加到购物车中,调用payServlet进行商品结算
- 2.当用户甲访问购物网站时,服务器为甲创建了一个Session信息(相当于购物车),当甲将Nokia手机添加到购物车网站时,Nokia手机的信息便存放到了Session对象中
- 3.同时服务器将Session对象的ID属性以Cookie(Set-Cookie:JSESSIONID=111)的形式返回给浏览器
- 4.当甲完成购物进行结账时,需要向服务器发送结账请求,这时浏览器自动在请求头中将Cookie信息回送给服务器,服务器根据ID属性找到为用户甲所创建的Session对象,并将Session对象中所存放的Nokia手机信息取出来进行结算,用户乙同理
- 4.HttpSession API
- 1.HttpServletRequest定义了用于获取Session对象的getSession方法
- 2.该方法有两种重载方式
//根据传递的参数判断是否创建新的HttpSession对象,如果参数为true,则在相关的HttpSession对象不存在时创建并返回新的HttpSession对象,否则不创建新的HttpSession对象,返回null public HttpSession getSession() //在相关的HttpSession对象不存在时总是创建新的HttpSession对象 public HttpSession getSession() //注意:getSession()方法可能会产生发送会话标识号的Cookie头字段,因此必须在发送任何响应内容之前调用getSession()方法
- 3.HttpSession接口中定义了操作会话数据的常用方法
方法声明 功能描述 String getId() 该方法用于返回与当前HttpSession对象关联的会话标识号 long getCreationTime() 该方法用于返回Session创建的时间,这个时间是创建Session的时间与1970年1月1日00:00:00之间时间差的毫秒表示形式 long getLastAccessedTime() 该方法用于返回客户端最后一次发送与Session相关请求的时间,这个时间是发送请求的时间与1970年1月1日00:00:00之间时间差的毫秒表示形式 void setMaxInactiveInterval(int interval) 该方法用于设置当前HttpSession对象可空闲的以秒为单位的最长时间(即:修改当前会话的默认超时间隔) boolean isNew() 该方法用于判断当前HttpSeesion对象是否是新创建的 void invalidate() 该方法用于强制使Session对象无效 ServletContext getServletContext() 该方法用于返回当前HttpSession对象所属于的Web应用程序对象(即:代表当前Web应用程序的ServletContext对象) void setAttribute() 该方法用于将一个对象与一个名称关联后存储到当前的HttpSession对象中 String getAttribute() 该方法用于从当前HttpSession对象中返回指定名称的属性对象 void removeAttribute(String name) 该方法用于从当前HttpSession对象中删除指定名称的属性 - 5.Session超时管理
- 1.客户端第一次访问某个能开启会话功能的资源时,Web服务器就会创建一个与该客户端对应的HttpSession对象
- 2.HTTP协议中,Web服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭(即:即使客户端离开或关闭了浏览器,Web服务器还要保留与之对应的HttpSession)
- 3.随着时间的推移,这些不再使用的HttpSession对象会在Web服务器中积累的越来越多,从而使Web服务器内存耗尽;为了解决这种问题,Web服务器采用了超时限制的办法来判断客户端是否还在继续访问
- 4.超时限制:指在一定的时间内,如果某个客户端一直没有请求访问,则Web服务器就会认为该客户端的请求已经结束,并且将该客户端会话所对应的HttpSession对象变成垃圾对象,等待垃圾收集器将其从内存中彻底清除;反之如果浏览器超时后,再次向服务器发出请求访问,那么Web服务器则会创建一个新的HttpSession对象,并为其分配一个新的ID属性
- 5.会话的有效时间可以在web.xml文件中设置,其默认值由Servlet容器定义,在Tomcat安装目录/conf/web.xml文件中可以找到该配置信息
- 语法说明:
- 1.设置的时间值是以分钟为单位(即:Tomcat服务器的默认会话超时间隔为30分钟)
- 2.如果将< session-timeout>元素中的时间值设置成0或一个负数,则表示会话永不超时
- 3.Tomcat安装目录/conf/web.xml文件对站点内的所有Web应用程序都起作用
- 4.如果想单独设置某个Web应用程序的会话超时间隔,则需在自己应用的web.xml文件中进行设置,内容同上
- 5.如果想使Session失效,除了可以等待会话时间超时外,还可以通过invalidate()方法强制使会话失效
3.实现购物车
4.实现用户登录
7.Servlet应用
1.Servlet读取HTML表单数据
- 2.Servlet中调用HttpServletRequest的getParameter方法,在调用参数中提供表单元素的名字即可读取数据
- 3.getParameter(String name)方法的返回值是一个字符串,是参数中指定的变量名字第一次出现所对应的值
- 1.如果指定的表单变量存在,但是没有值,getParameter就会返回空字符串
- 2.如果指定的表单变量不存在,则返回null
- 4.如果表单变量可能对应多个值,可以用getParameterValues方法,它能够返回一个字符串数组
- 5.HttpServletNames方法可以获得完整的表单变量名字列表,getParameterNames返回的是一个Enumeration,其中的每一项都可以转换为调用getParameter的字符串
1.Servlet读取指定HTML表单数据
- register.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>注册页面</title> </head> <body> <table border=1 align=center> <form action="Register" name="register" method="post" onsubmit="return check()"> <tr> <th colspan="2">用户注册</th> </tr> <tr> <td>用户名:</td> <td><input type="text" name="username" size=11></td> </tr> <tr> <td>密码:</td> <td><input type="password" name="pwd1" size=18 ></td> </tr> <tr> <td>确认密码:</td> <td><input type="password" name="pwd2" size=18 ></td> </tr> <tr> <td>电子邮箱:</td> <td><input type="email" name="email" size=18 ></td> </tr> <tr> <td>性别:</td> <td> <input type="radio" name="sex" value="boy">男 <input type="radio" name="sex" value="girl">女 </td> </tr> <tr> <td>教育程度:</td> <td> <select name="edu"> <option value="c">本科</option> <option value="h">高中</option> <option value="s">初中</option> </select> </td> </tr> <tr> <td><input type="submit" name="submit" value="提交"></td> <td><input type="reset" name="reset" value="重置" ></td> </tr> </form> </body> </html>
- RegisterServlet.java
package servletDemo; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class RegisterServlet extends HttpServlet{ /** * */ private static final long serialVersionUID = 775147027821523486L; public RegisterServlet() { } public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String pwd1 = (String)request.getParameter("pwd1"); String pwd2 = (String)request.getParameter("pwd2"); if(pwd1.equals(pwd2)) { out.println("<html>"); out.println("<head><title>Read All Parameter</title></head>"); out.println("<body>"); out.println("<h3 align=center>All Patameter From Request</h3>"); out.println("<table border=1 align=center>"); out.println("<tr><th>Parameter Name</th><th>Patameter Value</th></tr>"); Enumeration enumNames = request.getParameterNames(); while(enumNames.hasMoreElements()) { int i = 0; String strParam = (String) enumNames.nextElement(); String[] strValue = request.getParameterValues(strParam); out.println("<tr>"); out.println("<td>"+strParam+"</td>"); out.println("<td>"+strValue[i++]+"</td>"); out.println("<tr>"); } out.println("</table>"); out.println("</body>"); out.println("</html>"); }else { out.println("<h3>两次输入的密码不一致,请重新输入</h3>"); out.println("<h3>5秒后跳转到注册页面,如果失败请点击以下链接手动进入</h3>"); out.println("<a href=register.html>注册页面</a>"); response.setHeader("refresh", "5,register.html"); } } }
- web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>MyselfWeb</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>Register</servlet-name> <servlet-class>servletDemo.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Register</servlet-name> <url-pattern>/Register</url-pattern> </servlet-mapping> </web-app>
- 结果
正确结果
错误结果
8.Filter过滤器
1.Filter定义
- 1.Filter过滤器其实就是一个实现了javax.servlet.Filter接口的类,用于对request,response对象进行修改
- 2.Filter过滤器功能是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet进行响应处理前后实现一些特殊功能
- 说明:
1.浏览器访问服务器中的目标资源时会被Filter拦截,在Filter中进行预处理操作然后再将请求转发给目标资源
2.服务器接收到这个请求后会对其进行响应,在服务器处理响应过程中,也需要先将响应结果发送给过滤器,在过滤器中对响应结果进行处理后,才会发送给客户端
方法声明 功能描述 init(FilterConfig filterConfig) 该方法用来初始化过滤器,可以完成与构造方法类似的初始化功能; 如果初始化代码中要使用FilterConfig对象,那么这些初始化代码只能在Filter的init()方法中编写,而不能在构造方法中编写 doFilter(ServletRequest request,ServletResponse response,FilterChain chain) 该方法有多个参数;request和response参数为Web服务器或Filter链中的上一个Filter传递过来的请求和响应对象;chain参数代表当前Filter链对象,在当前Filter对象中的doFilter()方法内部需调用FilterChain对象的doFilter()方法,才能把请求交付给Filter链中的下一个Filter或者目标程序去处理 destroy() 该方法在Web服务器卸载Filter对象之前被调用,用于释放被Filter对象打开的资源 - 3.以上3个方法是Filter的生命周期方法:
- 1.init()方法在Web应用程序加载的时候调用
- 2.destroy()方法在Web应用程序卸载的时候调用,这两个方法都只会被调用一次
- 3.doFilter()方法只要客户端请求就会被调用,并且Filter所有的工作集中在doFilter()方法中
2.Filter映射
- 1.filter拦截的资源需要在web.xml文件中进行配置,这些配置信息就是Filter映射
- 2.Filter映射方式分为两种
- 1.使用通配符*拦截用户的所有请求
<filter> <filter-name>FirstFilter</filter-name> <filter-class>filter.FirstFilter</filter-class> </filter> <filter-mapping> <filter-name>FirstFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
- 语法说明:
- 1.
<filter>
根元素用于注册一个Filter- 2.
<filter-name>
子元素用于设置Filter名称- 3.
<filter-class>
子元素用于设置Filter类的完整名称- 4.
<filter-mapping>
根元素用于设置一个过滤器所拦截的资源- 5.
<filter-name>
子元素必须与<filter>
中<filter-name>
子元素相同- 6.
<url-pattern>
子元素用于匹配用户请求的URL
- 1.匹配原则类似servlet映射
- 2.区别是Filter过滤器的
<url-pattern>
相当于servlet的<url-pattern>
设置<servlet> <servlet-name>FilterServlet</servlet-name> <servlet-class>servletDemo.FilterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FilterServlet</servlet-name> <url-pattern>/FilterTest/adv</url-pattern> </servlet-mapping> <filter> <filter-name>FirstFilter</filter-name> <filter-class>filter.FirstFilter</filter-class> </filter> <filter-mapping> <filter-name>FirstFilter</filter-name> <url-pattern>/FilterTest/*</url-pattern> </filter-mapping>
- FilterServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub PrintWriter out = response.getWriter(); out.println("Hello FilterServlet"); }
- FirstFilter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here PrintWriter out = response.getWriter(); out.println("Filter Success"); // pass the request along the filter chain //chain.doFilter(request, response); }
- 2.拦截不同方式的访问请求
- 1.web.xml文件中,一个< filter-mapping>元素用于配置一个Filter所负责拦截的资源
- 2.< filter-mapping>元素中有一个特殊的子元素< dispatcher>,该元素用于指定过滤器所拦截的资源被Servlet容器调用的方式,< dispatcher>元素的值共有4个:
- 1.REQUEST:
- 当用户直接请求访问页面时,Web容器会调用该过滤器
- 如果目标资源是通过RequestDipatcher的include()或forward()方法访问的,该过滤器将不会调用
- 2.INCLUDE:
- 如果目标资源是通过RequestDispathcer的include()方法访问的,那么该过滤器将被调用;除此之外,该过滤器不会调用
- 3.FORWARD:
- 如果目标资源是通过RequestDispathcer的forward()方法访问的,那么该过滤器将被调用;除此之外,该过滤器不会调用
- 4.ERROR:
- 如果目标资源是通过声明式异常处理机制调用的,那么该过滤器将被调用;除此之外,该过滤器不会调用
<servlet> <servlet-name>FilterServlet</servlet-name> <servlet-class>servletDemo.FilterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FilterServlet</servlet-name> <url-pattern>/FilterTest/adv</url-pattern> </servlet-mapping> <filter> <filter-name>FirstFilter</filter-name> <filter-class>filter.FirstFilter</filter-class> </filter> <filter-mapping> <filter-name>FirstFilter</filter-name> <url-pattern>/FilterTest/*</url-pattern> <!--<dispatcher>REQUEST</dispatcher>--> <dispatcher>INCLUDE</dispatcher> </filter-mapping>
- ForwardServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub RequestDispatcher dispatcher = request.getRequestDispatcher("/first.jsp"); dispatcher.forward(request, response); }
- first.jsp
<body> <p>Forward Test</p> <p>this is first</p> </body>
<servlet> <servlet-name>Forward</servlet-name> <servlet-class>servletDemo.ForwardServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Forward</servlet-name> <url-pattern>/Forward</url-pattern> </servlet-mapping> <filter> <filter-name>FirstFilter</filter-name> <filter-class>filter.FirstFilter</filter-class> </filter> <filter-mapping> <filter-name>FirstFilter</filter-name> <url-pattern>/first.jsp</url-pattern> <!-- <dispatcher>FORWARD</dispatcher>--> </filter-mapping>
3.Filter链
- 1.一个Web应用程序中可以注册多个Filter程序,每个Filter程序都可以针对一个URL进行拦截
- 2.如果多个Filter程序都对同一个URL进行拦截,那么这些FIlter就会组成一个Filter链(也叫过滤器链)
- 3.Filter链用FilterChain对象来表示,FilterChain对象中有一个doFilter()方法,该方法就是让Filter链上的当前过滤器放行,使请求进入下一个FIlter或Web应用,否则只会显示该过滤器的内容而无法使请求跳转到下一个页面
- 语法说明:
- 1.浏览器访问Web服务器中的资源时,需要经过两个过滤器Filter1和Filter2
- 2.首先Filter1会对请求进行拦截,在Filter1过滤器的doFilter()方法中处理好请求后,通过调用FIlter1的doFilter()方法中的chain.doFilter()方法将请求传递给FIlter2,Filter2将用户请求处理后同样调用chain.doFilter()方法,最终将请求发送给目标资源
- 3.Web服务器对该请求做出响应时也会被过滤器拦截,这个拦截顺序与请求相反,最终将响应结果发送给客户端
- 4.Filter链中的各个Filter的对Servletd的拦截顺序与它们在web.xml文件中< filter-mapping>元素的映射顺序一样(即:顺序位于上面的Filter先拦截,优先级依次降低)
- 5.chain.doFilter()方法上面的语句是对request对象的拦截,下面是对response对象的拦截,两个拦截时的顺序相反(即:对request对象的拦截顺序和该Filter在xml文件配置顺序一样,而response对象刚好相反)
- 6.请求拦截时读取的是chain.doFilter()方法上面的信息,响应拦截时读取的是chain.doFilter()方法下面的信息
- 7.chain.doFilter()方法将处理将给下一个页面,如果没有该方法,则不会跳转到下一个页面,只会显示拦截信息
- 8.Filter链中的各个Filter的对文件修改的优先级与它们在web.xml文件中< filter-mapping>元素的映射顺序一样(即:顺序位于上面的Filter修改的内容可以对面的所有内容生效,而下面的Filter修改的内容无法对上面的Filter内容生效)
- 9.Servlet与Filter不存在顺序关系,即:不管Servlet在web.xml文件中位于Filter上面还是下面,Servlet只要映射匹配都可以被Filter拦截过滤
- 4.测试
- 1.MyFilter1.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here PrintWriter out = response.getWriter(); out.println("Hello MyFilter1 Before"); // pass the request along the filter chain chain.doFilter(request, response); out.println("Hello MyFilter1 After"); }
- 2.MyFilter2.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here PrintWriter out = response.getWriter(); out.println("Hello MyFilter2 Before"); // pass the request along the filter chain chain.doFilter(request, response); out.println("Hello MyFilter2 After"); }
- 3.web.xml
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>servletDemo.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/MyServlet2</url-pattern> </servlet-mapping> <filter> <filter-name>Myfilter2</filter-name> <filter-class>filter.MyFilter2</filter-class> </filter> <filter-mapping> <filter-name>Myfilter2</filter-name> <url-pattern>/MyServlet2</url-pattern> </filter-mapping> <filter> <filter-name>Myfilter1</filter-name> <filter-class>filter.MyFilter1</filter-class> </filter> <filter-mapping> <filter-name>Myfilter1</filter-name> <url-pattern>/MyServlet2</url-pattern> </filter-mapping>
- MyFilter1配置顺序在前
- MyFilter2配置顺序在前
- MyServlet配置顺序在前
4.FilterConfig接口
- 1.Servlet API提供FilterConfig接口获取Filter程序在web.xml文件中的配置信息
- 2.该接口封装了Filter程序在web.xml中的所有注册信息,并且提供了一系列获取这些配置信息的方法
方法声明 功能描述 String getFilterName() 该方法用于返回web.xml文件中为Filter所设置的名称,也就是返回< filter-name>元素的设置值 String getInitParameter(String name) 该方法用于返回web.xml文件中为Filter所设置的某个名称的初始化参数值,如果指定名称的初始化参数不存在,则返回null Enumeration getInitParameterNames() 该方法用于返回一个Enumeration集合对象,该集合对象中包含在web.xml文件中为当前Filter设置的所有初始化参数的名称 ServletContext getServletContext() 该方法用于返回FilterConfig对象中所包装的ServletContext对象的引用 - 1.web.xml
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>servletDemo.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/MyServlet2</url-pattern> </servlet-mapping> <filter> <filter-name>Myfilter3</filter-name> <filter-class>filter.MyFilter3</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>context-type</param-name> <param-value>text/html</param-value> </init-param> </filter> <filter-mapping> <filter-name>Myfilter3</filter-name> <url-pattern>/MyServlet2</url-pattern> </filter-mapping> <filter> <filter-name>Myfilter2</filter-name> <filter-class>filter.MyFilter2</filter-class> </filter> <filter-mapping> <filter-name>Myfilter2</filter-name> <url-pattern>/MyServlet2</url-pattern> </filter-mapping> <filter> <filter-name>Myfilter1</filter-name> <filter-class>filter.MyFilter1</filter-class> </filter> <filter-mapping> <filter-name>Myfilter1</filter-name> <url-pattern>/MyServlet2</url-pattern> </filter-mapping>
- 1.MyFilter1.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here PrintWriter out = response.getWriter(); out.println("Hello MyFilter1 Before" + "<br/>"); // pass the request along the filter chain chain.doFilter(request, response); out.println("测试Hello MyFilter1 After" + "<br/>"); }
- 2.MyFilter2.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here PrintWriter out = response.getWriter(); out.println("Hello MyFilter2 Before" + "<br/>"); // pass the request along the filter chain chain.doFilter(request, response); out.println("Hello MyFilter2 After" + "<br/>"); }
- 3.MyFilter3.java
public class MyFilter3 implements Filter { private String characterEncoding; FilterConfig fc; public MyFilter3() { // TODO Auto-generated constructor stub } public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); characterEncoding = fc.getInitParameter("encoding"); Enumeration e = fc.getInitParameterNames(); while(e.hasMoreElements()) { String name = (String) e.nextElement(); out.println(name + "<br/>"); } String name = fc.getFilterName(); out.println(name + "<br/>"); // pass the request along the filter chain out.println("encoding初始化参数的值为:" + characterEncoding + "<br/>"); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub this.fc = fConfig; } }
- 4.MyServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub PrintWriter out = response.getWriter(); out.println("Hello MyServlet" + "<br/>"); }
- 语法说明:
- 1.Tomcat服务器启动时会加载所有的Web应用,当加载到该应用时,MyFilter3就会被初始化调用init()方法,从而可以得到FIlterConfig,然后在doFilter()方法中通过调用FilterConfig对象的getInitParameter()方法便可以获取在web.xml文件中配置的某个参数信息
- 2.配置初始化参数一般在< xxx-class>后面配置,一个参数需要一个< init-param>
5.使用Filter实现用户自动登录
6.使用Filter实现统一全站编码