当我们使用 Servlet
进行开发的时候,能掌握一些 Servlet
的相关对象的话,就可以帮助我们更好的进行开发,其实最主要的也没有几个,就是 ServletConfig
、ServletContext
、HttpServletRequest
以及 HttpServletResponse
这几个了,如果能熟练掌握使用这几个对象的话,开发的时候解决问题的手段也会多很多。
1.ServletConfig
ServletConfig
对象可以用来获取在 web.xml
文件中配置的 Servlet
的一些信息,首先看如何在 Servlet
对象中获取到 ServletConfig
对象,其实在 HttpServlet
的父类 javax.servlet.GenericServlet
中是定义了一个方法来获得 ServletConfig
对象的,那就是
public ServletConfig getServletConfig()
通过这个方法我们就可以获取得到 ServletConfig
对象了,所以要想在 Servlet
对象当中获取到 ServletConfig
对象,就可以直接使用 this.getServletConfig();
这样的方式了,在 ServletConfig
对象中还有几个常用的 API
方法:
public String getInitParameter(String name) // 通过初始化参数的名称获取到对应的值
public java.util.Enumeration<E> getInitParameterNames() // 获取到初始化参数中所有的名称
public String getServletName() // 获取到当前Servlet的名称
要想测试上面的几个方法,首先可以这样来配置一个 Servlet
:
<servlet>
<servlet-name>ServletConfigTest</servlet-name>
<servlet-class>servletconfig.ServletConfigTest</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletConfigTest</servlet-name>
<url-pattern>/ServletConfigTest</url-pattern>
</servlet-mapping>
然后在对应的 Servlet
类中使用 ServletConfig
对象获取到 Servlet
中的配置信息:
public class ServletConfigTest extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 1.获得ServletConfig对象
ServletConfig config = this.getServletConfig();
String username = config.getInitParameter("username");
String password = config.getInitParameter("password");
System.out.println(username + " " + password);
// 2.获取所有初始化参数的名称和值
Enumeration<String> names = config.getInitParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
String value = config.getInitParameter(name);
System.out.println(name + " " + value);
}
// 3.获得Servlet的名称
String servletName = config.getServletName();
System.out.println("该Servlet的名称是:" + servletName);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
2.ServletContext
上面的 ServletConfig
是用来读取对应的 Servlet
配置信息的,而这里介绍的 ServletContext
则保存的是整个 web
项目的信息,一个 web
项目只有一个 ServletContext
对象,服务器会为每一个 web
项目创建一个 ServletContext
对象,下面根据 ServletContext
不同的作用分别来进行说明:
2.1 获取web项目信息
先看一下如何获取得到 ServletContext
对象,和上面的 ServletConfig
对象的获取相同,在 Servlet
的父类 javax.servlet.GenericServlet
中也有一个 API
方法可以获取到 ServletContext
对象,那就是:
public ServletContext getServletContext()
因此,如果想在当前的 Servlet
当中获取得到 ServletContext
对象的话,就可以直接使用 this.getServletContext();
这样的方式了。
2.1.1 获取文件的MIME类型
要想获取到文件的 MIME
类型,可以使用下面的这个方法:
public String getMimeType(String file)
这个方法就可以用来获取到指定文件的 MIME
类型,文件的 MIME
类型是由 Servlet
容器的配置来确定的,当前我们使用的 Servlet
容器就是 Tomcat
服务器了,所以文件的 MIME
类型也就是由 Tomcat
服务器的配置文件来指定的,想要查看的话就到 Tomcat
安装目录里面的 conf/web.xml
文件里面查看。
使用编码方式获得文件的 MIME
类型就可以使用下面的代码:
// 1.获取到ServletContext对象
ServletContext servletContext = this.getServletContext();
String mimeType = servletContext.getMimeType("aa.txt");
System.out.println(mimeType);
2.1.2 获取请求路径中的工程名
要想获得请求路径中的项目名,就可以使用 ServletContext
对象的 getContextPath()
方法,方法的详细如下:
public String getContextPath()
通过这个方法就可以在 Servlet
中得到当前的项目名称了,示例代码如下:
// 2.获取请求路径的工程名
String path = servletContext.getContextPath();
System.out.println(path);
2.1.3 获取全局初始化参数的配置
上面介绍的 ServletConfig
对象是用来获取与它相对应 Servlet
对象的初始化参数的,但是每一个 ServletConfig
对象获取得到的都是单个 Servlet
对象自己的初始化参数配置,那要是共有的一些初始化配置呢?显然就不能通过 ServletConfig
对象来进行获取了,那要如何获取呢?就是通过这里的 ServletContext
对象了。
首先在 web.xml
文件当中需要加入一些全局的初始化参数配置。
<context-param>
<param-name>username</param-name>
<param-value>Tom</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123</param-value>
</context-param>
下面就可以使用 ServletContext
对象来进行获取全局的初始化参数配置了。主要可以使用的方法是以下两个,其实和 ServletConfig
对象的十分类似。
public String getInitParameter(String name) // 根据初始化参数的名称来获取对应的值
public java.util.Enumeration<E> getInitParameterNames() // 获取所有初始化参数的名称,返回类型是一个枚举类型
代码示例如下:
// 3.获取全局初始化参数
String username = servletContext.getInitParameter("username");
String password = servletContext.getInitParameter("password");
System.out.println(username + " " + password);
Enumeration<String> names = servletContext.getInitParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
String value = servletContext.getInitParameter(name);
System.out.println(name + " " + value);
}
2.2 获取web项目下的文件
开发 web
项目的时候都会有很多的配置文件,比如关于连接数据库的配置文件 (db.properties)
,假定这个文件是放在 src
目录下的,那我们应该如何读取到这个文件之中的连接数据库信息呢?首先看一下 db.properties
文件中的信息:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/web_test
username=root
password=123456
读取上面这个文件当中的配置信息,第一想到的就应该是 IO
流了,那就和 Java
项目中加载配置信息一样直接使用 java.util.Properties
这个类来做吧,代码就如下:
Properties properties = new Properties();
InputStream is = new FileInputStream("src/db.properties");
properties.load(is);
String driverClassName = properties.getProperty("driverClassName");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(driverClassName);
System.out.println(url);
System.out.println(username);
System.out.println(password);
上面的程序是写在 doGet()
方法之中的,当有请求访问这个 Servlet
时,上面的代码就会执行,当我们在浏览器中输入地址发送请求之后却发现报错了!错误信息是:java.io.FileNotFoundException: src\db.properties (系统找不到指定的路径。)
很显然就是路径错误导致找不到 db.properties
这个文件了。为什么会出现这个错误呢?这是因为 web
项目是需要发布到 Tomcat
容器中才能被访问到的,而我们开发的 web
项目在被发布到 Tomcat
中之后和我们在使用 Eclipse
中进行开发时是不一样的,大家可以打开 Tomcat
的 webapps
目录,在里面找到对应的项目就会发现发布的 web
项目目录结构是怎样的,当前我们这个项目在发布之后的项目结构是这样的:
web_test
|--META-INF
|--WEB-INF
从这里就可以看出根本就没有 src
这个目录,所以我们上面的代码才会出错,当我们在查看文件的时候发现 db.properties
这个文件是在 web_test/WEB-INF/classes
目录下的,那我们加载这个文件的时候这样写是不是就好了呢?
InputStream is = new FileInputStream("/WEB-INF/classes/db.properties");
最后却发现还是报同样的找不到文件错误,这是什么原因呢?这就是因为我们所写的路径其实是相对路径,相对的是 JRE
环境,这时候 JRE
是交给 Tomcat
管理的,也就是此时相对的路径是 Tomcat
安装目录的 /bin
目录,这里是没有 db.properties
这个文件的,因此会报找不到文件错误,此时可以在这个 /bin
目录下新建 /WEB-INF/classes/db.properties
这个文件,然后再启动 /bin
目录下的 startup.bat
命令,然后在浏览器地址栏输入刚才的请求的路径,就会发现可以正常加载到配置文件了,不过如果是使用 Eclipse
启动项目的话却发现还是会报错,这里我也还没有完全搞明白为什么。
前面给的解决方法就是在 Tomcat
的安装路径 bin
目录下放置相应的配置文件,但是这样做肯定是不合理的,配置文件写在所属的项目中才是最好的,那这里就可以使用 ServletContext
来加载配置文件了。其中的方法为:
public java.io.InputStream getResourceAsStream(String path)
这个方法就是将路径上的配置文件转换为流的形式返回,这样就能加载到相关的文件了。
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
其实 ServletContext
的 API
中还提供了一个方法,就是将相对路径转换为绝对路径。
public String getRealPath(String path)
获取到配置文件的绝对路径之后,再用 FileInputStream
去加载该配置文件同样也可以获取的到。
其实要想加载到配置文件还有一种办法,那就是使用 Class
这个类,它其中有一个方法是:
public InputStream getResourceAsStream(String name)
这样也是可以加载到我们上面的配置文件的。
InputStream is = this.getClass().getResourceAsStream("/db.properties");
加载配置文件时指定的资源位置是 /db.properties
,这里所指的位置也就是 classpath
的位置,也就是我们 web
项目在被编译之后的 classes
目录里面。
2.3 作为域对象存取数据
web
服务器会为每一个 web
项目创建一个 ServletContext
对象,也就是说 ServletContext
的作用范围是整个 web
项目,当我们把数据存到这个对象上面的时候,那我们就可以在这个项目的很多地方取到数据了。关于使用 ServletContext
对象作为域对象来存取数据有关的 API
方法主要是以下几个:
public void setAttribute(String name, Object object) // 为ServletContext对象设置属性名以及相应的属性值对象
public Object getAttribute(String name) // 从ServletContext对象中根据属性名取出相应的属性值对象
public void removeAttribute(String name) // 从ServletContext对象中移除相应的属性
通过上面的方法我们就可以在同一个 web
项目的多个地方访问到同一个 ServletContext
对象以及其中的各个属性了。
要想测试的话,就可以使用两个 Servlet
对象,在其中的一个中写:
this.getServletContext().setAttribute("name", "Kobe");
另一个当中写:
String name = (String) this.getServletContext().getAttribute("name");
然后分别访问两个 Servlet
,就可以测试出 ServletContext
是否具有共享数据的功能了。
3.HttpServletResponse
下面就要介绍非常重要的两个对象了,分别就是我们 B/S
架构中的请求对象和响应对象,这肯定是非常重要的,因为浏览器和服务器进行通信时是使用的 HTTP
协议,而 HTTP
协议就是基于请求与响应模式的,下面就先介绍响应了 (HttpServletResponse)
。
3.1 HttpServletResponse的常用API方法
对于一个响应来说,是可以分为响应行、响应头和响应体这三部分的,Response
对象中也有分别对应这三个方面的方法,下面就进行列举并说明。
3.1.1 关于响应行的方法
一个响应的响应行中一般包括协议以及协议版本、状态码和状态码描述,我们使用 Response
对象的方法对响应行进行设置的话一般是设置的状态码,因此就可以使用下面这个方法:
public void setStatus(int sc)
比较常见的状态码就是下面这些:
200:响应成功
302:重定向
304:查找本地缓存
404:请求资源不存在
500:服务器内部错误
3.1.2 关于响应头的方法
关于响应头的方法的话可以简单的分为两类,一类是以 set
开头的方法,另一类则是以 add
开头的方法,以 set
开头的方法是用于一个 key
对应一个 value
的情况的,而以 add
开头的方法是用于一个 key
对应多个 value
的情况的,先看以 set
开头的方法:
public void setDateHeader(String name, long date)
public void setHeader(String name, String value)
public void setIntHeader(String name, int value)
再看以 add
开头的方法:
public void addDateHeader(String name, long date)
public void addHeader(String name, String value)
public void addIntHeader(String name, int value)
要说明这两类方法之间的差别的话,可以先从一个例子入手,假定现在已经有一个响应头为 Content-Type:text/html
,如果执行以 set
开头的方法的话 setHeader("Content-Type","text/plain");
,那么所得的结果应该是 Content-Type:text/plain
;而如果执行以 add
开头的方法的话 addHeader("Content-Type","text/plain");
,那么所得的结果就应该是 Content-Type:text/html,text/plain
了。
一句话总结的话,对于原来已经有值的响应头来说,使用以 set
开头的方法就相当于是替换,而使用以 add
开头的方法则相当于是追加。
3.1.3 关于响应体的方法
HttpServletResponse
对象还有两个用来响应浏览器请求的方法,不过都不在 HttpServletResponse
这个接口当中,而都是在它的父接口 ServletResponse
当中。
public ServletOutputStream getOutputStream()
public java.io.PrintWriter getWriter()
可以很容易看出,第一个方法是以字节形式返回数据,而第二个方法则是以字符形式来返回数据。
3.1.4 其它的一些方法
还有一些其它的方法值得介绍,比如重定向、设定字符集的以及操作 Cookie
的方法。
重定向:
public void sendRedirect(String location)
设置浏览器打开页面时采用的字符集:
public void setContentType(String type)
设定响应字符流的缓冲区编码:
public void setCharacterEncoding(String charset)
服务器向浏览器回写 Cookie
的方法:
public void addCookie(Cookie cookie)
需要注意一下的就是 setContentType()
和 setCharacterEncoding()
都是在 HttpServletResponse
的父接口 ServletResponse
中的方法。
3.2 使用HttpServletResponse实现一些小案例
这里其实还是为了测试一下上面所说的一些方法,比如设置响应的状态码。
response.setStatus(404);
这样就将状态码设置为了 404
,但是如果要想实现一些功能的话,简单地像这样设置状态码还是不行的,还是需要配合使用一些其它的响应头。
3.2.1 重定向
要想完成重定向功能,就可以使用我们前面了解到的 302
状态码,然后结合使用 Location
这个响应头就能完成了。示例代码如下:
response.setStatus(302);
response.setHeader("Location", "/web_test/ResponseDemo2");
这里完成的是从一个 Servlet
里面重定向到了另一个 Servlet
。不过由于在实现重定向时 302
状态码和 Location
响应头都是固定的,所以在实际开发中也可以使用 sendRedirect()
方法来实现重定向功能,示例代码如下:
response.sendRedirect("/web_test/ResponseDemo2");
3.2.2 定时刷新
如果想要在某个时间之后跳转到其它的 Servlet
的话,那就可以使用 Refresh
这个响应头了。具体示例如下:
response.setHeader("Refresh", "5;url=/web_test/ResponseDemo2");
上面的代码就是要在 5
秒之后跳转到 ResponseDemo2
这个 Servlet
里面,其实还可以在这句代码之前写上 5秒之后跳转...
这样的提示信息,同时因为提示信息中含有中文,就需要设置浏览器打开页面所使用的的字符编码,那完整的代码差不多应该是这样了。
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print("5秒之后跳转...");
response.setHeader("Refresh", "5;url=/web_test/ResponseDemo2");
这样在页面上显示提示信息 5
秒之后就会像上面一样跳转到另一个 Servlet
里面了。
上面就是实现了在后台从一个 Servlet
中跳转到另一个 Servlet
上,并且还可以在页面上给出像 5秒之后跳转
这样的提示信息,其实在前台页面之中也可以实现页面的跳转,并且还可以呈现出数秒的效果,具体的实现可以用两个 html
页面来测试。直接将代码粘贴到下面了。
demo1.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Refresh" content="5;url=/web_test/demo2.html">
<title>Insert title here</title>
<script type="text/javascript">
var second = 5;
function load(){
timer = window.setInterval("changeSecond()",1000);
}
function changeSecond(){
second--;
if (second > 0) {
document.getElementById("span1").innerHTML = second;
} else {
window.clearInterval(timer);
}
}
</script>
</head>
<body onload="load()">
<h1>Demo1.html</h1>
<h1><span id="span1">5</span>秒钟后跳转到demo2.html页面</h1>
</body>
</html>
demo2.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>跳转到的页面</title>
</head>
<body>
<h1>Demo2.html</h1>
</body>
</html>
当然实现的重点就在于 <meta http-equiv="Refresh" content="5;url=/web_test/demo2.html">
以及之后的 JavaScript
代码了,这样就能在页面上看到数秒的效果并且实现页面的跳转。
3.3 HttpServletResponse对象响应中文乱码处理
之前在介绍 Response
对象的响应体方法时说道有两种方法可以向浏览器回写数据,就是下面两种:
public ServletOutputStream getOutputStream()
public java.io.PrintWriter getWriter()
第一个方法 getOutputStream()
很显然就是以字节流的方式回写数据了,而第二个方法 getWriter()
很显然则是以字符流的方式回写数据了,那它们这两种方式在向浏览器回写中文的时候是否会出现乱码呢?下面分开来进行说明。
3.3.1 字节流方式
使用字节流方式向浏览器回写中文字符应该是像下面这样:
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write("中文".getBytes());
那这样的情况是否会产生乱码呢?其实是不一定的,要看中文转为字节数组时采用的字符集编码和浏览器打开页面时所使用的字符集编码是否一致,像上面 "中文".getBytes()
这样将中文字符转换为字节数组时因为没有指定采用哪一种字符集,则会使用默认的,也就是当前项目采用的字符集编码,而当前并没有指定浏览器以何种字符集打开页面,因此也会使用浏览器中设置的默认值,如果这两者刚好一致的话,那就不会产生乱码了,而如果两者不一致的话,就会产生乱码,因此这里解决乱码的方式也就是设置中文字符转换为字节数组采用的字符集编码以及浏览器打开页面时使用的编码,并且要保证二者设置是一致的。
首先设置中文字符转换为字节数组时采用哪种字符集编码:
"中文".getBytes("UTF-8")
再设置浏览器采用哪种字符集编码打开页面:
response.setHeader("Content-Type", "text/html;charset=UTF-8");
这样设置完之后就能保证使用字节流回写中文字符时不产生乱码了,比较完整的代码如下:
ServletOutputStream outputStream = response.getOutputStream();
response.setHeader("Content-Type", "text/html;charset=UTF-8");
outputStream.write("中文".getBytes("UTF-8"));
3.3.2 字符流方式
使用字符流向浏览器回写中文字符应该是像下面这样:
response.getWriter().print("中文");
那以这种字符流的方法向浏览器回写中文字符是否会产生乱码呢?答案是一定会产生。这是因为以字符流方式回写数据的时候,Response
对象是有字符串缓冲区的,而这个缓冲区默认采用的字符集编码是 ISO8859-1
,这个字符集编码是根本就不支持中文字符的,因此就一定会产生中文字符乱码的现象,那如何才能解决这个问题呢?很明显就是将 Response
对象字符串缓冲区的字符集编码修改成支持中文字符的,而且还要将浏览器打开页面时使用的字符集编码也修改为这一个,以保证两者是一致的,比如都修改为 UTF-8
这个字符集编码。
首先设置 Response
对象的字符串缓冲区编码:
response.setCharacterEncoding("UTF-8");
再设置浏览器打开页面时使用的字符集编码:
response.setHeader("Content-Type", "text/html;charset=UTF-8");
使用上面两步就能保证使用字符流方式向浏览器回写中文字符时不产生中文乱码了,比较完整的代码如下:
response.setHeader("Content-Type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().print("中文");
这里还需要注意的一点就是在使用字符流方式向浏览器回写数据的时候,上面代码的前两句其实可以使用一句代码来替换的,所起的效果是一样的。
response.setContentType("text/html;charset=UTF-8");
4.HttpServletRequest
上面是说完了服务器响应浏览器的响应对象 (Response)
,那这里就开始说一下浏览器向服务器发送请求的请求对象 (Request)
,主要是介绍其中的 API
方法以及对相关方法进行测试,最后也是说明一下如何解决中文字符乱码的问题。
4.1 HttpServletRequest的常用API方法
主要是介绍 Request
对象两个方面的 API
方法,一个是获取请求参数的,当浏览器向服务器发送请求的时候,一般都会带有请求参数以及对应的值,比如提交一个表单数据,这时候我们要想保存表单中提交的数据,则必定需要获取到表单中参数所对应的值;第二个则是 Request
作为域对象存值、取值以及移除值的一些方法。当然还有其它一些比如获得客户机信息以及获得请求头的方法。
4.1.1 获取客户机信息的方法
有时候我们需要知道一些客户机浏览器的信息,那该如何获取呢?其实在 HttpServletRequest
对象中就提供了许多这样的方法,比如如何知晓浏览器请求的方式是什么?到底是 GET
方式请求,还是 POST
方式请求,这时候我们就可以通过下面的方法来获得请求方式:
public String getMethod()
获得请求路径后提交参数的字符串
public String getQueryString()
获取请求路径的 URL
和 URI
public StringBuffer getRequestURL()
public String getRequestURI()
获得客户机的 IP
地址,这个方法是在父接口 ServletRequest
中
public String getRemoteAddr()
4.1.2 获取请求头信息的方法
浏览器发送请求中的请求头一般是以键值对的形式出现的,而这里一般是分为两种情况,一种是一个 key
对应一个 value
,而另一种则是一个 key
对应多个 value
,所以主要是通过下面两个方法:
public String getHeader(String name)
public java.util.Enumeration<E> getHeaders(String name)
通过上面两个方法就可以得到相关的请求头了。
4.1.3 获取请求参数的方法
浏览器向服务器发送请求时可能是带有请求参数以及对应的值的,所以我们就必须在服务器端的 Servlet
中接收到相应的请求参数以及值,具体的方法有如下这些:
接收一个参数对应一个值的方法:
public String getParameter(String name)
接收一个参数对应多个值的方法:
public String[] getParameterValues(String name)
接收参数和值组成的 Map
集合方法:
public java.util.Map<K, V> getParameterMap()
4.1.4 作为域对象存取数据的方法
最开始介绍的 ServletContext
也是可以作为域对象的,不过它所表示的范围是比较大的,是整个 web
项目,而这里的 Request
同样也可以作为域对象,不过它的范围就要小得多,表示的是一次请求,但却是非常实用的,应用也非常多,下面来看一下 Request
作为域对象的 API
方法:
首先是向 Request
中保存数据:
public void setAttribute(String name, Object o)
然后则是从 Request
中取出数据:
public Object getAttribute(String name)
最后则是从 Request
中移除数据:
public void removeAttribute(String name)
4.2 HttpServletRequest中常用API方法测试
首先是请求方式的测试,这里可以直接在浏览器的地址栏输入要访问的 Servlet
地址,这里就是 GET
方式的请求了,如果想用 POST
方式发送请求,则可以借助于 postman
等谷歌浏览器插件。
// 获取请求方式
System.out.println("请求方式:" + request.getMethod());
其它的方法其实只要使用一下就知道效果了,直接把测试代码放在下面吧。
// 获得客户端的IP地址
System.out.println("客户端的IP地址:" + request.getRemoteAddr());
// 获得请求路径中的请求参数字符串
System.out.println("请求参数字符串:" + request.getQueryString());
// 获取请求路径的URL和URI
System.out.println("请求路径的URL:" + request.getRequestURL());
System.out.println("请求路径的URI:" + request.getRequestURI());
// 获取请求头的信息
System.out.println("客户机浏览器类型:" + request.getHeader("User-Agent"));
4.3 HttpServletRequest接收表单数据
使用 HttpServletRequest
对象的时候,还有一个比较重要的应用就是接收前台表单数据,在实际开发中很多情况都需要进行表单数据提交操作,比如用户登录时,也是将用户名和密码等信息放在一个 form
表单之中,然后再进行提交,下面就完成一个表单数据提交的例子。
前台页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>request对象接收表单数据</title>
</head>
<body>
<h1>request对象接收表单数据</h1>
<form action="/web_test/RequestDemo2" method="post">
用户名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password"/><br/>
性别:<input type="radio" name="sex" value="man" />男
<input type="radio" name="sex" value="woman" />女<br/>
籍贯:<select name="city">
<option value="beijing">北京市</option>
<option value="shenzhen">深圳市</option>
<option value="shanghai">上海市</option>
</select><br/>
爱好:<input type="checkbox" name="hobby" value="basketball"/>篮球
<input type="checkbox" name="hobby" value="football"/>足球
<input type="checkbox" name="hobby" value="volleyball"/>排球<br/>
自我介绍:<textarea name="info" rows="5" cols="10"></textarea><br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
后台 Servlet(RequestDemo2)
:
public class RequestDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 接收用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
String sex = request.getParameter("sex");
String city = request.getParameter("city");
// 接收爱好
String[] hobby = request.getParameterValues("hobby");
// 接收自我介绍
String info = request.getParameter("info");
System.out.println("用户名:" + username);
System.out.println("密码:" + password);
System.out.println("性别:" + sex);
System.out.println("籍贯:" + city);
System.out.println("爱好:" + Arrays.toString(hobby));
System.out.println("自我介绍:" + info);
// 用getParameterMap()接收数据
Map<String, String[]> map = request.getParameterMap();
for (String key : map.keySet()) {
String[] value = map.get(key);
System.out.println(Arrays.toString(value));
}
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
4.4 HttpServletRequest对象解决中文字符乱码
在使用表单提交数据时,如果输入框中有中文,那么不管是使用 GET
方式还是 POST
方式发送请求,都会产生乱码,但是两者产生乱码的原因却是不一样的,下面分开来说。
4.4.1 POST方式提交中文字符
在使用 POST
方式提交数据时,会将数据放在请求体中传到后台,同时请求的数据也是放在 request
对象的字符串缓冲区之中的,而这个缓冲区默认的字符集编码是 ISO8859-1
,这个字符集是不支持中文字符的,因此在传输中文数据时才会产生中文乱码,而要解决这个问题也就好办了,直接将 request
字符串缓冲区采用的字符集编码改为 UTF-8
就好了,因为这个是支持中文的,而且我项目也是设置的使用该字符集编码。
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
4.4.2 GET方式提交中文字符
在使用 GET
方式提交数据时,是将传输的参数名称和值都拼接在请求路径的后面,而在传输中文字符时,浏览器还会使用 UTF-8
这个字符集对中文字符进行一次编码,比如如果需要传输的参数是 name
,而且其对应的值是 学生
,那么在浏览器的地址栏中请求的完整路径应该是:
http://localhost:8080/web_day10/RequestDemo3?name=%E5%AD%A6%E7%94%9F
虽然在诸如谷歌的 Chrome
浏览器之中看到的完整请求路径可能还是:
http://localhost:8080/web_day10/RequestDemo3?name=学生
这是因为 Chrome
浏览器又将中文字符解码为原始值的样式展示了,其实如果对那个完整请求路径进行复制的话,粘贴的时候就会发现,原来确实是使用 UTF-8
这个字符集进行编码过了的,有一些浏览器,比如 IE
就直接将编码之后的内容展示在地址栏,这样就会直观的看到是有对中文字符进行编码的过程的。
下面开始说产生乱码的原因,在浏览器地址栏对中文字符进行一次编码之后,还会将它们放到 request
对象的字符串缓冲区中,上面已经说过这个缓冲区的字符集编码默认是 ISO8859-1
,因此为了得到原来正确的中文字符,我们要对 request
缓冲区中的中文字符使用 ISO8859-1
进行编码,然后再使用 UTF-8
对它进行一次解码就可以得到原来的中文字符了。
String name = request.getParameter("name");
String encode = URLEncoder.encode(name, "ISO8859-1");
name = URLDecoder.decode(encode, "UTF-8");
上面的后两句代码如果不太熟的话,其实还可以利用 String
类的构造方法进行简单操作。
String result = new String(name.getBytes("ISO8859-1"),"UTF-8");
实际开发中也是这种方式较多,其实只要记住后一种简便方法就好了。
下面就将 GET
方式和 POST
方式提交中文字符的代码放在这里。
demo2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>request处理中文乱码</title>
</head>
<body>
<h1>request处理中文乱码</h1>
<h3>以POST方式提交数据</h3>
<form action="/web_test/RequestDemo3" method="post">
姓名:<input type="text" name="name"/><br/>
<input type="submit" value="提交" />
</form>
<h3>以GET方式提交数据</h3>
<form action="/web_day10/RequestDemo3" method="get">
姓名:<input type="text" name="name"/><br/>
<input type="submit" value="提交" />
</form>
</body>
</html>
RequestDemo3:
public class RequestDemo3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("name");
// String encode = URLEncoder.encode(name, "ISO8859-1");
// name = URLDecoder.decode(encode, "UTF-8");
String result = new String(name.getBytes("ISO8859-1"),"UTF-8");
System.out.println("姓名:"+result);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
System.out.println("姓名:"+name);
}
}
5.总结
这篇文章主要介绍了 Servlet
的相关对象,主要有四个对象:ServletConfig
、ServletContext
、HttpServletResponse
以及 HttpServletRequest
。其实记住它们可以做什么就比较好理解了,ServletConfig
可以用来获取当前 Servlet
的配置信息,ServletContext
则是用来获取当前项目的全局配置信息,同时它作为域对象也可以用来存取整个项目范围类的数据,HttpServletResponse
则是表示服务器对客户机浏览器的响应,主要是用来对浏览器发送响应信息,HttpServletRequest
就是表示浏览器对服务器的一次请求,并且其中还包含了同时提交的数据,作为域对象则可以在一次请求范围内存取数据,最后的重点则是 response
对象和 request
对象的乱码处理,这点一定要弄清楚乱码产生的原因以及如何解决乱码。