JavaWeb(二):Servlet
一、本教程使用的Web容器——Tomcat
Tomcat是提供一个支持Servlet和JSP运行的容器。Servlet和JSP能根据实时需要,产生动态网页内容。而对于Web服务器来说, Apache仅仅支持静态网页,对于支持动态网页就会显得无能为力;Tomcat则既能为动态网页服务,同时也能为静态网页提供支持。尽管它没有通常的Web服务器快、功能也不如Web服务器丰富,但是Tomcat逐渐为支持静态内容不断扩充。大多数的Web服务器都是用底层语言编写如C,利用了相应平台的特征,因此用纯Java编写的Tomcat执行速度不可能与它们相提并论。一般来说,大的站点都是将Tomcat与Apache的结合,Apache负责接受所有来自客户端的HTTP请求,然后将Servlets和JSP的请求转发给Tomcat来处理。Tomcat完成处理后,将响应传回给Apache,最后Apache将响应返回给客户端。
1.1 Tomcat访问静态资源
tomcat访问所有的资源,都是用Servlet来实现的。
在Tomcat看来,资源分3种:
- 静态资源,如css,html,js,jpg,png等
- Servlet
- JSP
运行应用程序的Web容器将会有一个或多个内建的Servlet,这些Servlet用于处理JavaServer Pages、显示目录列表(如果启用了该功能的话)和访问静态资源,例如HTML页面和图片。
JspServlet用于处理JSP页面,DefaultServlet是处理静态资源的Servlet,在tomcat的conf目录下web.xml:
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet> <!-- The mapping for the default servlet -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <!-- The mappings for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
1.2 安装tomcat
配置jdk环境变量
下载,解压,目录结构如下:
bin目录 可执行文件,如启动tomcat
conf目录 配置文件
lib目录 第三方依赖的jar包
logs目录 日志
temp目录 临时文件
webapps目录 部属的web应用
work目录 jsp翻译成servlet再翻译成class的文件
双击bin中的startup.bat可以启动tomcat
若已经启动一个tomcat应用,再启动同一个tomcat应用,会抛出端口占用异常
用bin中的shutdown.bat可以关闭tomcat
修改端口号
server.xml
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
1.3 Tomcat中JavaWeb目录结构
1.3.1 目录结构
创建的Web项目,必须有一个根目录,根目录下:
- *.html、*.jsp等外部可以公开访问的文件,看成公开目录
- WEB-INF/web.xml,必须要有, 部属描述符
- WEB-INF/classes,编译后的Java类文件,可选
- WEB-INF/lib,Java类库文件
WEB-INF/目录中的文件是受到保护的,不能通过URL访问。
1.3.2 手工创建一个web项目
用eclipse创建一个普通java工程
创建com.aidata包,并创建Person类
package com.aidata; public class Person { public String getPersonInfo() {
return "person info...";
}
}
下面手工创建tomcat项目目录
创建WebContent根目录
创建WEB-INF目录
创建目录WEB-INF/classes,创建com文件夹,com下创建aidata文件夹,将eclipse的bin目录下生成的Person.class拷贝过来
创建目录WEB-INF/lib
从tomcat拷贝一个web.xml到WEB-INF目录下
在根目录下创建一个jsp页面
<%@page import="com.aidata.Person"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body> <%
Person person = new Person();
System.out.println(person.getPersonInfo());
%> </body>
</html>
将根目录拷贝到tomcat的webapps目录下
启动tomcat
浏览器输入http://localhost:8080/WebContent/hello.jsp,命令行窗口会打印
Tomcat8 IDEA 乱码
IDEA控制台乱码:找到IDEA的 idea64.exe.vmoptions 文件,添加 -Dfile.encoding=UTF-
浏览器乱码:确保html或jsp文件保存的编码格式为UTF-8,可以notepad++转为utf-8编码格式
二、了解Servlet
Java Web项目的构成:
- 需要自己的代码和它依赖的第三方库
- Servlet、JSP、过滤器、监听器......
- HTML、JS、CSS......
- 部属描述符,其中包含了部属和启动应用程序的指令
- 可以添加ClassLoader用于将自己的应用程序与同一台服务器上的其他Web应用程序隔离
- 通过某种方式将应用程序打包,生成WAR和EAR文
Servlet是JavaEE规范的一种,主要是为了扩展Java作为Web服务的功能。Servlet就是一群人来制定java应用中使用web时的各种规范,统一接口,其他内部实现由厂商自己实现,tomcat、jetty、jboss等等应运而生,面向接口编程。我们讲Servlet,默认是说Servlet实现,Servlet的实现是一个运行在Web服务器中的Java小程序,接收和响应来自Web客户端的请求,使用HTTP进行通信。
可以这么理解,JCP指定规范,提供接口,Web容器厂商实现了Web接收、响应等功能,我们实现具体的业务逻辑功能。
2.1 Servlet容器与Servlet
Servlet容器为Java Web应用提供运行时环境,它负责管理Servlet和JSP的生命周期,以及管理它们的共享数据,从下图可知,客户Web浏览器只与Web容器打交道。
Servlet生命周期相关方法,这些方法都是Servlet容器负责调用:
- 构造器:第一次请求Servlet时,创建Servlet实例,调用构造器,只被调用一次,单例
- init方法:只被调用一次,在创建好实例后立即被调用,用于初始化当前Servlet
- service:被多次调用,每次请求都会调用,实际用于响应请求
- destroy:只被调用一次,在当前Servlet所在的WEB应用被卸载前调用,用于释放当前Servlet所占用的资源
Servlet容器响应客户请求:
2.2 Servlet的API
API包含了两个软件包,十二个接口和九个类。
软件包:javax.servlet
所包含的接口:RequestDispatcher;Servlet;ServletConfig;ServletContext;ServletRequest;ServletResponse;SingleThreadModel。
所包含的类:GenericServlet;ServletInputStream;ServletOutputStream;ServletException;UnavailableException。
软件包:javax.servlet.http
所包含的接口:HttpServletRequest;HttpServletResponse;HttpSession;HttpSessionBindingListener;HttpSessionContext。
所包含的类:Cookie;HttpServlet;HttpSessionBindingEvent;HttpUtils。
三、创建第一个Servlet——只实现Servlet接口的最简单Servlet
步骤:
- 新建web项目
- 在src中新建包,包下新建类,该类实现Servlet接口,重写要实现的方法
- 配置web.xml
3.1 创建Web项目
3.1.1 Eclipse
不使用Maven:https://www.cnblogs.com/greenteaone/p/7929908.html
使用Maven:https://blog.csdn.net/huijiahekele/article/details/78589680
3.1.2 IDEA
不使用Maven:https://www.cnblogs.com/cangqinglang/p/10027199.html
使用Maven:
创建maven项目
配置tomcat
选project structure
选tomcat
去 Apache网站 http://tomcat.apache.org/whichversion.html 查看tomcat的servlet版本
Servlet Spec | JSP Spec | EL Spec | WebSocket Spec | Authentication (JASIC) Spec | Apache Tomcat Version | Latest Released Version | Supported Java Versions |
---|---|---|---|---|---|---|---|
5.0 | 3.0 | 4.0 | 2.0 | 2.0 | 10.0.x | 10.0.0-M5 (alpha) | 8 and later |
4.0 | 2.3 | 3.0 | 1.1 | 1.1 | 9.0.x | 9.0.35 | 8 and later |
3.1 | 2.3 | 3.0 | 1.1 | 1.1 | 8.5.x | 8.5.55 | 7 and later |
3.1 | 2.3 | 3.0 | 1.1 | N/A | 8.0.x (superseded) | 8.0.53 (superseded) | 7 and later |
3.0 | 2.2 | 2.2 | 1.1 | N/A | 7.0.x | 7.0.104 | 6 and later (7 and later for WebSocket) |
2.5 | 2.1 | 2.1 | N/A | N/A | 6.0.x (archived) | 6.0.53 (archived) | 5 and later |
2.4 | 2.0 | N/A | N/A | N/A | 5.5.x (archived) | 5.5.36 (archived) | 1.4 and later |
2.3 | 1.2 | N/A | N/A | N/A | 4.1.x (archived) | 4.1.40 (archived) | 1.3 and later |
2.2 | 1.1 | N/A | N/A | N/A | 3.3.x (archived) | 3.3.2 (archived) | 1.1 and later |
根据servlet版本配置 web.xml
3.0
<?xml version="1.0" encoding="UTF-8"?>
<web-app
version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> </web-app>
4.0
<?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"> </web-app>
pom.xml中加入jstl和standard依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency> <dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
在JSP页面引入核心标签库的代码为:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
开启EL表达式:<%@page isELIgnored="false"%>
3.2 实现Servlet接口
需要实现的方法:
- public void init(ServletConfig servletConfig) 初始化,只会调用一次
- public ServletConfig getServletConfig() 返回一个 ServletConfig 对象,该对象用来返回初始化参数和 ServletContext。ServletContext 接口提供有关 servlet 的环境信息。
- public void service(ServletRequest servletRequest, ServletResponse servletResponse) 核心方法
- public String getServletInfo() 可选,它提供有关 servlet 的信息,如作者、版本、版权。
- public void destroy() Servlet卸载前调用
- 可以编写构造方法
package com.aidata.javawe; import javax.servlet.*;
import java.io.IOException; public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init");
} @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() {
System.out.println("getServletInfo");
return null;
} @Override
public void destroy() {
System.out.println("destroy......");
} // 构造器
public HelloServlet(){
System.out.println("HelloServlet's constructor");
}
}
init(ServletConfig servletConfig)方法
第一个请求到达之时Servlet启动,init方法在Servlet构造完成之后调用。显然,如果init方法要完成大量工作,当第一个请求达到时,init方法执行会花大量时间。
ServletConfig:封装了Servle的t配置信息,并且可以获取ServletContext对象
ServletContext接口:
一个Web应用程序中的所有Servlet都共享同一个ServletContext对象,所以,ServletContext对象被称之为 application 对象(Web应用程序对象)。
Servlet引擎为每个Web应用程序都创建一个对应的ServletContext对象,ServletContext对象被包含在ServletConfig对象中,调用ServletConfig.getServletContext方法可以返回ServletContext对象的引用。
功能:
可以认为是当前Web的一个大管家,可以获得当前Web应用各个方面的信息
- ·获取WEB应用程序的初始化参数
- ·记录日志
- ·application域范围的属性
- ·访问资源文件
- ·获取虚拟路径所映射的本地路径
- ·Web应用程序之间的访问
- ·ServletContext的其他方法
获取当前web应用的某一个文件在服务器上的绝对路径,而不是部属前的路径:
getRealPath(String path)
String realPath = servletContext.getRealPath("/index.jsp");
System.out.println(realPath);
结果
C:\Users\JieZ\IdeaProjects\WebDemo\out\artifacts\firstweb_war_exploded\index.jsp
注意是在out路径里
获取当前WEB应用的名称:
String contextPath = servletContext.getContextPath();
System.out.println(contextPath);
获取当前WEB应用的某一个文件对应的输入流:
getResourceAsStream(String path): path的/为当前的根目录
try {
ClassLoader classLoader = getClass().getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");
System.out.println("1." + is);
}catch (Exception e){
e.printStackTrace();
} try {
InputStream is2 = servletContext.getResourceAsStream("/WEB-INF/classes/jdbc.properties");
System.out.println("2." + is2);
}catch (Exception e){
e.printStackTrace();
}
结果
1.java.io.BufferedInputStream@400c929d
2.java.io.FileInputStream@7d42e4bb
3.3 在web.xml中配置Servlet
Servlet程序必须通过Servlet容器来启动运行,并且储存目录有特殊要求,通需要存储在<WEB应用程序目录>\WEB-INF\classes\目录中。 Servlet程序必须在WEB应用程序的web.xml文件中进行注册和映射其访问路径,才可以被Servlet引擎加载和被外界访问。
web.xml中重要的两个标签:
- <servlet>元素用于注册一个Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
- <servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定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"> <!-- 配置和映射Servlet -->
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.aidata.javawe.HelloServlet</servlet-class> </servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。
配置步骤
- 向描述符中添加Servlet
- 将Servlet映射到URL
load-on-startup参数
前面提到过init方法如果有大量工作,当一个请求达到时才开始执行,会大大影响请求回应的效率
可以指定Servlet被创建的时机,若为负数,则在第一次请求时被创建,若为0或正数,则在当前WEB应用被Servlet容器加载时创建实例。当多个Servlet配置都包含该标签,它们将按照标签内的值的大小顺序启动,且数值越小越早被创建。
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.aidata.javawe.HelloServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
Servlet的初始化参数
可以在web.xml中的servlet标签的init-param子标签内配置Servlet的初始化参数
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.aidata.javawe.HelloServlet</servlet-class> <!--配置Servlet的初始化参数,且该节点必须在load-on-startup的前面-->
<init-param>
<!--参数名-->
<param-name>user</param-name>
<!--参数值-->
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>1230</param-value>
</init-param>
<load-on-startup>-1</load-on-startup>
</servlet>
获取Servlet初始化参数
servletConfig.getInitParameter(String name):获取指定参数名的初始化参数
servletConfig.getInitParameterNames():获取参数名组成的Enumeration对象
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init");
String user = servletConfig.getInitParameter("user");
System.out.println("user:"+user); Enumeration<String> names = servletConfig.getInitParameterNames();
while (names.hasMoreElements()){
String name = names.nextElement();
String value = servletConfig.getInitParameter(name);
System.out.println("^^"+name+":"+value);
}
}
结果
init
user:root
^^password:1230
^^user:root
Web应用的初始化参数
可以在web.xml中配置整个应用的初始化参数
使用标签:
<context-param>
<param-name>xxx</param-name>
<param-value>xxx</param-value>
</context-param>
<?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"> <!--配置当前Web应用的初始化参数-->
<context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>
<context-param>
<param-name>jdbcUrl</param-name>
<param-value>jdbc:mysql:///aidata</param-value>
</context-param> <!-- 配置和映射Servlet -->
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.aidata.javawe.HelloServlet</servlet-class> <!--配置Servlet的初始化参数,且该节点必须在load-on-startup的前面-->
<init-param>
<!--参数名-->
<param-name>user</param-name>
<!--参数值-->
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>1230</param-value>
</init-param>
<load-on-startup>-1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
获取整个应用的初始化参数则使用:
servletContext.getInitParameter(String name):获取指定参数名的初始化参数
servletContext.getInitParameterNames():获取参数名组成的Enumeration对象
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init"); ServletContext servletContext = servletConfig.getServletContext();
String driver = servletContext.getInitParameter("driver");
System.out.println("driver:"+driver); Enumeration<String> name2 = servletContext.getInitParameterNames();
while (name2.hasMoreElements()){
String name = name2.nextElement();
System.out.println("--->"+name);
}
}
这里设置的初始化参数可以被所有的Servlet所获取,而Servlet的初始化参数只有那个Sevlet可以获取
四、HTTP、ServletRequest和ServletResponse
4.1 HTTP协议、Get方法和Post方法
Web浏览器与Web服务器之间的一问一答的交互过程必须遵循一定的规则,这个规则就是HTTP协议,HTTP是超文本传输协议的简写,它是TCP/IP协议集中的一个应用层协议,用于定义Web浏览器与Web服务器之间交换数据的过程以及数据本身的格式。
HTTP协议的版本HTTP/1.0、HTTP/1.1、HTTP-NG
请求数据包
响应数据包
响应状态码
HTTP的会话方式
浏览器访问多图页面的过程,每个图片都是一对单独的请求和响应:
Get和Post
GET请求把请求参数附在url的后面,用?连接,是一个个键值对。在浏览器地址栏中输入某个URL地址或单击网页上的一个超链接时,浏览器发出的HTTP请求消息的请求方式为GET,使用GET方式传递的数据量一般限制在1KB以下。
Post主要用于传递表单信息,传递的信息要大的多。
4.2 ServletRequest和ServletResponse
我们知道了浏览器会像服务端发送HTTP请求,那么我们的Servlet是如何处理请求的呢?
两个接口:
ServletRequest:封装了请求信息,可以从中获取到任何的请求信息。官方文档http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/ServletRequest.html
ServletResponse:封装了响应信息,如果想给给用户什么响应,具体可以使用接口的方法实现。官方文档http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/ServletResponse.html
这两个接口的实现类,都是服务器给予实现的,并在服务器调用service方法时传入。
ServletRequest
封装了请求信息. 可以从中获取到任何的请求信息。
获取请求参数
String getParameter(String name)
根据请求参数的名字, 返回参数值,
该方法只能获取到第一个提交的值,若请求参数有多个值(例如 checkbox), 要用下一个方法
HTML
<form action="loginServlet" method="post">
user: <input type="text" name="user"/>
password: <input type="text" name="password">
<input type="submit" value="Submit"/>
</form>
Servlet
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("请求来了...");
System.out.println(servletRequest);
String user = servletRequest.getParameter("user");
String password = servletRequest.getParameter("password");
System.out.println(user + "," + password);
}
结果
"请求来了..."
org.apache.catalina.connector.RequestFacade@44fe4cd9
john,123
String[] getParameterValues(String name)
根据请求参数的名字, 返回请求参数对应的字符串数组。
需要一组参数,用多选框。
HTML
<form action="loginServlet" method="post">
user: <input type="text" name="user"/>
password: <input type="text" name="password">
<br><br>
interesting:
<input type="checkbox" name="interesting" value="reading"/>Reading
<input type="checkbox" name="interesting" value="game"/>Game
<input type="checkbox" name="interesting" value="party"/>Party
<input type="checkbox" name="interesting" value="sport"/>Sport
<input type="checkbox" name="interesting" value="tv"/>TV
<input type="submit" value="Submit"/>
</form>
Servlet
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("请求来了..."); String interesting = servletRequest.getParameter("interesting");
System.out.println(interesting);
String[] interestings = servletRequest.getParameterValues("interesting");
for (String interest: interestings){
System.out.println("-->" + interest);
}
}
结果
"请求来了..."
reading
-->reading
-->game
-->party
-->sport
Enumeration getParameterNames()
返回参数名对应的 Enumeration 对象,
类似于 ServletConfig(或 ServletContext) 的 getInitParameterNames() 方法。
Map getParameterMap()
返回请求参数的键值对,
key:参数名, value: 参数值, String 数组类型。
Servlet
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("请求来了..."); String[] interestings = servletRequest.getParameterValues("interesting");
for (String interest: interestings){
System.out.println("-->" + interest);
}
Enumeration<String> names = servletRequest.getParameterNames();
while (names.hasMoreElements()){
String name = names.nextElement();
String val = servletRequest.getParameter(name);
System.out.println("^^"+name + ": " + val);
}
Map<String, String[]> map = servletRequest.getParameterMap();
for (Map.Entry<String, String[]> entry: map.entrySet()){
System.out.println("**" + entry.getKey() + ":" + Arrays.asList(entry.getValue()));
}
}
结果
-->reading
-->game
-->party
-->sport
^^user: zhaojie
^^password: 123
^^interesting: reading
**user:[zj]
**password:[123]
**interesting:[reading, game, party, sport]
HttpServletRequest
是 SerlvetRequest 的子接口,针对于 HTTP 请求所定义,里边包含了大量获取 HTTP 请求相关的方法。
获取请求的 URI
获取请求方式
httpServletRequest.getMethod()
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String requestURI = httpServletRequest.getRequestURI();
System.out.println(requestURI); String method = httpServletRequest.getMethod();
System.out.println(method);
结果
/firstweb/loginServlet
POST
若是一个 GET 请求, 获取请求参数对应的那个字符串, 即?后的那个字符串
String queryString = httpServletRequest.getQueryString();
System.out.println(queryString);
结果
user=aidata&password=123456&interesting=game&interesting=party&interesting=shopping
获取请求的 Serlvet 的映射路径
String servletPath = httpServletRequest.getServletPath();
System.out.println(servletPath);
结果
/loginServlet
attribute 相关的几个方法
ServletResponse
封装了响应信息, 如果想给用户什么响应, 具体可以使用该接口的方法实现。
getWriter()
返回 PrintWriter 对象. 调用该对象的 print() 方法, 将把 print() 中的参数直接打印到客户的浏览器上。
设置响应的内容类型
response.setContentType("application/msword");
指定为word类型,点击提交会下载word文档
servletResponse.setContentType("application/msword"); //word类型
PrintWriter out = servletResponse.getWriter();
out.println("helloworld...");
void sendRedirect(String location)
请求的重定向. (此方法为 HttpServletResponse 中定义,需要强转)
五、从自定义GenericServlet到HttpServlet
5.1 编写一个Servlet,发现问题
在 web.xml 文件中设置两个Web应用的初始化参数user和password。定义一个 login.html, 里边定义两个请求字段: user, password. 发送请求到 loginServlet。创建一个 LoginServlet, 在其中获取请求的user和password,比对其和 web.xml 文件中定义的请求参数是否一致。若一致, 响应 Hello:xxx, 若不一致, 响应 Sorry: xxx xxx 为 user。
web.xml
<!-- 配置当前WEB应用初始化参数-->
<context-param>
<param-name>user</param-name>
<param-value>atguigu</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123567</param-value>
</context-param>
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.atguigu.javaweb.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
HTML
<form action="loginServlet" method="post">
user: <input type="text" name="username"/>
password: <input type="password" name="password">
<input type="submit" value="Submit"/>
</form>
<form action="loginServlet" ...>中的loginServlet是url不是Servlet的名称
Servlet
private ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig; // 为了在service方法中使用servletConfig
} @Override
public ServletConfig getServletConfig() {
return null;
} @Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
} @Override
public void destroy() {
// TODO Auto-generated method stub
} @Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//1.获取请求参数:username,password
String username = servletRequest.getParameter("username");
String password = servletRequest.getParameter("password");
//2.获取WEB应用的初始化参数:user,password
ServletContext servletContext = servletConfig.getServletContext();
String initUser = servletContext.getInitParameter("user");
String initPassword = servletContext.getInitParameter("password"); PrintWriter out = servletResponse.getWriter();
//3.比对
//4.打印响应字符串
if (initUser.equals(username) && initPassword.equals(password)){
out.println("Hello" + username);
}else {
out.println("sorry" + username);
}
}
我们发现当实现Servlet接口的时候,有很多方法如getServletInfo()根本用不到,但是还是不得不实现,导致了大量的空方法。
为了在service()中使用servletConfig,还定义了一个属性。
其实,有一个抽象类GenericServlet可以简化我们的工作。
官方文档http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/GenericServlet.html
5.2 编写自己的GenericServlet
方便开发,编写如下抽象类,实现Serclet和ServletConfig接口
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration; /**
* 自定义的一个Servlet接口的一个实现类,目标是让开发的任何Servlet都继承,以简化开发
*/
public abstract class MyGenericServlet implements Servlet, ServletConfig {
/**
* Servlet的方法
*/
private ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
} @Override
public ServletConfig getServletConfig() {
return null;
} @Override
public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException; @Override
public String getServletInfo() {
return null;
} @Override
public void destroy() {} /**
* ServletConfig接口的方法
*/ @Override
public String getServletName() {
return servletConfig.getServletName();
} @Override
public ServletContext getServletContext() {
return servletConfig.getServletContext();
} @Override
public String getInitParameter(String s) {
return servletConfig.getInitParameter(s);
} @Override
public Enumeration<String> getInitParameterNames() {
return servletConfig.getInitParameterNames();
} }
GenericServlet是Servlet接口和ServletConfig接口的实现类,但是一个抽象类,其中的service方法为抽象方法
如果新建的Servlet程序直接继承GenericServlet会使开发更简洁
官方具体实现:
- 在GenericServlet中声明了一个ServletConfig类的成员变量,在init(ServletConfig)方法中对器进行初始化
- 利用ServletConfig成员变量的方法实现了ServletConfig接口的方法
- 还定义了一个init()方法,在init(ServletConfig)方法中对其进行调用,子类可直接覆盖init()在其中实现对Servlet的初始化
- 不建议直接覆盖init(ServletConfig),因为如果忘记编写super(ServletConfig),而还是用了ServletConfig接口的方法,则会出现空指针异常
- 新建的init(){}并非Servlet的生命周期方法,而init(ServletConfig)是生命周期相关的方法
5.3 编写自己的HttpServlet
GenericServlet是一个不依赖具体协议的Servlet,它只包含了一个抽象的service方法和几个辅助方法。缺乏对HTTP的支持,比如,当ServletRequest想要获取请求方式是GET还是POST,需要调用HttpServlet,需要强转,还是麻烦。
编写一个支持HTTP的Servlet
/**
* 针对HTTP协议定义的一个Servlet类
*/
public class MyHttpServlet extends MyGenericServlet{
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
if (servletRequest instanceof HttpServletRequest){
HttpServletRequest request = (HttpServletRequest) servletRequest; if (servletResponse instanceof HttpServletResponse){
HttpServletResponse response = (HttpServletResponse)servletResponse;
service(request, response);
}}
} private void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException{
//1.获取请求方式
String method = servletRequest.getMethod();
//2.根据请求方式再创建对应的处理方法
if ("GET".equalsIgnoreCase(method)){
doGet(servletRequest, servletResponse);
}
if ("POST".equalsIgnoreCase(method)){
doPost(servletRequest, servletResponse);
} }
public void doGet(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException{ }
public void doPost(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { }
}
于是,只要继承上面的类就可以大大简化开发
public class LoginServlet2 extends MyHttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod(); //不再用强转
System.out.println(method); //1.获取请求参数:username,password
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("--------------" + username);
//2.获取WEB应用的初始化参数:user,password String initUser = getServletContext().getInitParameter("user");
String initPassword = getServletContext().getInitParameter("password"); PrintWriter out = resp.getWriter();
//3.比对
//4.打印响应字符串
if (initUser.equals(username) && initPassword.equals(password)){
out.println("Hello" + username);
}else {
out.println("sorry" + username);
}
}
}
上面的定义的类基本实现了一般开发中常用的HttpServlet
HttpServlet继承自GenericServlet,针对于HTTP协议定制
在service()方法中,直接把ServletRequest和ServletResponse转为HttpServletRequest和HttpServletResponse,并调用了重载的service(HttpServletRequest, HttpServletResponse)
在service(HttpServletRequest , HttpServletResponse)获取了请求方式:reque.getMethod(),根据请求方式又创建了doXxx()方法(Xxx为具体的请求方式,比如doGet、doPost)。
实际开发中,直接继承HttpServlet,并根据请求方式复写doXxx()方法接口
好处:直接有针对性覆盖doXxx()方法,直接使用HttpServletRequest和HttpServletResponse,不再需要强转
一个字:
棒!
JavaWeb(二):Servlet的更多相关文章
- JavaWeb之Servlet入门(二)
1. 准备 在JavaWeb之Servlet入门(一)中,我们完成了第一个Servlet程序,完成了从URL到后台控制器的中转过程,接下来我们延续JavaWeb之Servlet入门(一)学习下如何传参 ...
- IDEA新建javaWeb以及Servlet简单实现
刚开始用IDEA开发,还不太熟悉,因此写一个教程,加深印象 1.新建一个Web项目 两种方法:java 和 Java Enterprise(推荐) 第一种)通过Java工程创建,这个方法需要手动导入T ...
- JavaWeb学习——Servlet相关的接口和类
JavaWeb学习——Servlet相关的接口和类 摘要:本文主要学习了Servlet相关的接口和类. Servlet的接口和类 三种方式 实现Servlet有三种方式: 实现javax.servle ...
- javaweb(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册
一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp ...
- javaweb(六)——Servlet开发(二)
一.ServletConfig讲解 1.1.配置Servlet初始化参数 在Servlet的配置文件web.xml中,可以使用一个或多个<init-param>标签为servlet配置一些 ...
- javaweb学习总结二十二(servlet开发中常见的问题汇总)
一:web应用的映射问题 通常我们从别人那里拷贝来的代码,自己会修改应用的名称,但是web映射的访问路径并没有修改,还是原来的映射. 解决方法: 工程右键--properties--myeclipse ...
- 二SERVLET(2)
转载自http://www.cnblogs.com/xdp-gacl/p/3763559.html 一.ServletConfig讲解 1.1.配置Servlet初始化参数 在Servlet的配置文件 ...
- Intellij IDEA创建javaWeb以及Servlet简单实现
1.创建web工程 File --> New --> Project...
- JavaWeb之Servlet总结
今天上班居然迟到了,昨天失眠了,看完吐槽大会实在不知道做些什么,刚好朋友给我发了两个JavaWeb的练习项目,自己就又研究了下,三四点才睡,可能周日白天睡的太多了,早上醒来已经九点多了,立马刷牙洗脸头 ...
随机推荐
- Share架构的一些心得
个人这些年,从web->system service->app 项目实战,陆陆续续经历的项目很多,自己也数不清.自己也一直对于架构没有明确去给出一个自己的定义描述. 刚好最近一直在flut ...
- 前端二倍图的思考(涉及Retina)
EXCELL格式 1 csv格式导出来之后不能用EXCELL打开,会乱码.用记事本打开,然后将"(英文的引号出掉),就可以了. 关于二倍图的操作 概念: 设备像素:也叫物理像素,显示设备上最 ...
- Golang通过反射获取结构体的标签
Golang通过反射获取结构体的标签 例子: package main import ( "fmt" "reflect" ) type resume struc ...
- 大数据学习笔记之Zookeeper(三):Zookeeper理论篇(二)
文章目录 3.1 数据结构 3.2 节点类型 3.3 特点 3.4 选举机制 3.5 stat结构体 3.6 监听器原理 3.1 数据结构 ZooKeeper数据模型的结构与Unix文件系统很类似,整 ...
- PHP 开启错误显示并设置错误报告级别
警告:生产环境永远都不要显示任何错误信息! 显示错误(display_errors)和错误报告(error_reporting)是两回事.PHP 脚本发生错误时,可以根据设置选择是否报告这个错误(记录 ...
- CNN之池化层tf.nn.max_pool | tf.nn.avg_pool | tf.reduce_mean | padding的规则解释
摘要:池化层的主要目的是降维,通过滤波器映射区域内取最大值.平均值等操作. 均值池化:tf.nn.avg_pool(input,ksize,strides,padding) 最大池化:tf.nn.ma ...
- TCP协议-流量控制
流量控制是通过滑动窗口来实现控制的.使用了坚持定时器,防止发送失败导致死锁.
- [已解决]报错: Error response from daemon: conflict
报错内容: Error response from daemon: conflict: unable to delete f5b6ef70d79b (must be forced) - image i ...
- Manacher(最长镜面回文串)
I - O'My! Gym - 101350I Note: this is a harder version of Mirrored string I. The gorillas have recen ...
- [HDU 3625]Examining the Rooms (第一类斯特林数)
[HDU 3625]Examining the Rooms (第一类斯特林数) 题面 有n个房间,每个房间有一个钥匙,钥匙等概率的出现在n个房间内,每个房间中只会出现且仅出现一个钥匙.你能炸开门k次, ...