第六天 HttpServletResponse 和HttpServletRequest (1)
HttpServletResponse 接口 .................................................................................... 2 数据响应(重点) ...................................................................................................... 2 HttpServletRequest 接口 ....................................................................................... 7 请求获取(重点) ...................................................................................................... 8 Web 项目中路径问题 ........................................................................................... 18 URLEncoder 和URLDecoder 类 ......................................................................... 18 总结 ..................................................................................................................... 20 练习 (20)
第六天 HttpServletResponse 和HttpServletRequest
在Servlet 生命周期中我们只是简单的讲解了生命周期的几个方法以及对象的创建,下图详细的描述了客户端浏览器和服务器Tomcat 的请求和响应过程。
文字描述:
1.浏览器发送请求
2.服务器找到指定的网站,然后该网站的web.xml 中找到指定的资源名映射的Class 类 3.服务器检测该Class 是否有对象,如果有直接返回,如果没有直接创建 4.服务器创建ServletConfig 接口的实现类对象
5.服务器调用Servlet 的init(ServletConfig)方法进行初始化 6.创建HttpServletRequest 和HttpServletResponse 对象 7.服务器调用service 方法
8.在service 方法中响应用户的请求
9.执行完毕service 方法将response 返回给Tomcat 容器
IE 浏览器
Tom cat 服务器
Dem o1
1 : 192.168.10.1/day06/Dem o1()
2 : 在Tom cat 管理的网站中的web.xm l 找资源()
3 : 找到/Dem o1对应的class()
4 : 如果没有找到该类的实例,那么创建,否则直接返回该实例()
5 : 执行构造函数创建对象()
6 : 创建Servelt()
7 : 创建ServletConfig 对象()
8 : 执行init()
9 : 创建HttpServletRequest 和HttpServletResponse 对象()
10 : service 处理用户的请求,就是使用response 进行数据输出()
11 : 将写好数据的response 对象返回给Tocm at()
12 : 将response 中的数据使用HTTP 响应消息格式封装好()
13 : 响应用户的请求()
13结束后请求和响应结束,如果服务器关闭了,
那么销毁服务器创建好的所有对象:
ServletConfig 、ServletContext 、request 和response 以及servlet 的实例
GET /day07/MyResources HTTP/1.1
Accept: */*
Accept-Language: zh-cn,en-US;User-Agent: Mozilla/4.0
Accept-Encoding: gzip, deflate Host: localhost:8080
Connection: Keep-Alive
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1Content-Length: 0
Date: Fri, 02 Nov 2012 03:42:49
HTTPServletRequest
HttpServletResponse
10.服务器封装response响应数据为HTTP格式
11.服务器将封装为HTTP协议的响应数据发送给浏览器进行响应
12.服务器响应结束,如果关闭则销毁创建好的所有对象
13.整个请求和响应结束….
HttpServletRequest代表用户的请求(重点)
HttpServletResponse代表服务器的响应(重点)
HttpServletResponse接口
继承体系:
----| ServletResponse 接口
该接口主要定义了一个用于响应客户端请求的对象,该接口的对象由Tomcat创建并传递给service相关的方法。
获取输出流方法
ServletOutputStream getOutputStream() →给客户端响应二进制数据
PrintWriter getWriter() →给客户端响应文本数据
响应设置方法
void setCharacterEncoding(String charset) →设置输出数据的编码方式
void setContentType(String type) →设置响应的内容类型
------| HttpServletResponse 接口
该接口继承自ServletResponse接口,主要定义了用于获取响应消息头和Cookie的一些方法。该接口的对象由Tomcat创建传递给service相关的方法。
设置响应头方法
void setStatus(int sc) →设置响应的状态码
void setHeader(String name, String value) →设置响应头
添加Cookie方法
void addCookie(Cookie cookie) →添加Cookie信息
请求重定向方法
void sendRedirect(String location) →重定向请求
数据响应(重点)
◆设置响应状态码和响应头
1.重定向设置
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 设置响应的状态码
response.setStatus(302);
// 设置响应头
response.setHeader("location", "/day07/redirect");
}
特点:
(1) 浏览器发送了两次请求
(2) 浏览器地址栏发生了变化
缺点:
对于不懂得HTTP协议的人而言不好操作。
2.使用response提供的方法实现重定向
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
response.sendRedirect("/day07/redirect");
}
总结:
其实Servlet不主张直接操作HTTP协议,一般都会提供额外的方法来使得开发者简单(透明)的操作HTTP协议。
response.setHeader("content-type", "text/html;charset=UTF-8");
使用以下语句替换:
response.setContentType("text/html;charset=UTF-8")
字节流输出
1、普通数据输出
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 1. 获取字节输出流
ServletOutputStream out = response.getOutputStream();
// 2. 输出数据
String data = new String("hello");
out.write(data.getBytes());
data = "this is a h2
";
out.write(data.getBytes());
// 3. 释放资源
out.close();
}
2、中文的输出
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 0. 设置输出数据的编码方式(设置字节流)
response.setHeader("content-type",
"text/html;charset=UTF-8");
// 1. 获取字节输出流
ServletOutputStream out = response.getOutputStream();
// 2. 输出数据
String data = new String("hello");
out.write(data.getBytes());
data = "我的文章标题
";
out.write(data.getBytes("UTF-8")); // 编码
// 3. 释放资源
out.close();
}
多学一招:
该标签在HTML中模拟HTTP协议通知浏览器我的页面的编码方式。
也可以使用下列语句通知浏览器解码方式:
ServletOutputStream out = response.getOutputStream();
out.write("
content=\"text/html; charset=utf-8\" />".getBytes());
3、数字的输出
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 1. 获取字节输出流
ServletOutputStream out = response.getOutputStream();
// 2. 数字输出
out.write(97); // a
out.write("97".getBytes()); // 97
// 3. 释放资源
out.close();
}
4、发送图片数据
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 给浏览器发送二进制数据
ServletContext context = this.getServletContext();
String path = context.getRealPath("/images/0001.jpg");
InputStream in = new FileInputStream(path);
byte [] bs = new byte[1024];
int len = 0;
// 给浏览器输出
ServletOutputStream out = response.getOutputStream();
while((len=in.read(bs))!=-1){
out.write(bs,0,len);
}
// 释放资源
in.close();
out.close();
}
案例:实现校验码?
1.编写一个Servlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 0. 控制图片不能被缓存
response.setHeader("expires", -1+"");
response.setHeader("cache-control", "no-cache");
response.setHeader("pragma", "no-cache");
// 1. 在内存构建一个图片
BufferedImage image = new
BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
// 2. 获取内存中的图片
Graphics graphic = image.getGraphics();
// 3. 设置图片的背景
graphic.setColor(Color.WHITE);
graphic.fillRect(0, 0, 80, 20);
// 4. 给该图片进行文字的添加
graphic.setColor(Color.RED);
graphic.setFont(new Font(null,Font.BOLD,14));
graphic.drawString(getCode(4), 5, 15);
// 5. 将生成好的图片发送给浏览器
ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, "jpg",out )xxxxx`;
}
2.编写生成校验码的方法
private String getCode(int len){
// 1. 创建随机要生成的数据
String data = "我们中国人真很牛逼你相信吗反正我信元芳你怎么看";
StringBuffer sb = new StringBuffer();
// 2. 循环生成指定个数的字符
Random random = new Random();
for (int i = 0; i < len; i++) {
int count = random.nextInt(data.length());
sb.append( data.charAt(count) );
}
return sb.toString();
}
3.在页面中引入校验码
字符流输出
1.输出普通字符
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 1. 获取字符流
PrintWriter ps = response.getWriter();
// 2. 输出数据
String data = "this is a data";
ps.write(data);
// 3. 释放资源
ps.close();
}
2.输出中文
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 0. 设置字符流的输出编码方式
response.setCharacterEncoding("UTF-8"); // 编码
response.setContentType("text/html;charset=UTF-8"); // 解码
// 1. 获取字符流
PrintWriter ps = response.getWriter();
// 2. 输出数据
String data = "我是一个字符序列";
ps.write(data);
// 3. 释放资源
ps.close();
}
3.输出数字
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 1. 获取字符流
PrintWriter ps = response.getWriter();
// 2. 输出数字
ps.write(97); // a
// 3. 释放资源
ps.close();
}
4.使用细节1,同时获取字节流和字符流做用户的响应输出?
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 获取字节流
ServletOutputStream out = response.getOutputStream();
// 获取字符流
PrintWriter writer = response.getWriter();
// 使用字节流输出
out.write("hello".getBytes());
// 使用字符流进行输出
writer.write("world");
}
结果:
https://www.doczj.com/doc/466160207.html,ng.IllegalStateException: getOutputStream() has already been
called for this response
注意:在以下的代码中容易发生字节流和字符流的同时获取?
this.getServletContext().getRequestDispatcher("/welcome").forward(request, response);
5.使用细节2,关闭输出流?
如果使用close()方法将字节流或字符流显示的关闭,那么意味着响应结束,那么后续的输出都不会被执行。因此在实际的开发中由于Response是Tomcat创建的相应对象,那么我们开发者没有必要进行显示的关闭response对象获取的各种流对象。
总结:
1.请求转发和请求的重定向的区别
//请求转发特点:一次请求、地址栏不变,服务器转发。
this.getServletContext().getRequestDispatcher("/welcome").forward(request, response);
// 请求重定向特点:二次请求、地址栏变化,浏览器重新请求。
response.sendRedirect("/welcome");
2.不同的流输出中文的处理方式不同
// 通知流浏览器以指定的方式进行解码
response.setContentType(“text/html;charset=utf-8”)
// 通知服务器以指定的编码进行输出的编码(字符流)
response.setCharacterEncoding(“utf-8”)
HttpServletRequest接口
该接口主要描述的浏览器的请求信息。
----| ServletRequest 接口
该接口的对象代表浏览器客户端的请求信息,由Tomcat创建并以参数的形式传递给service相关的方法。
获取请求参数的方法
String getParameter(String name) →获取指定名字的参数
String[] getParameterValues(String name) →获取指定名字的所有参数值
Enumeration getParameterNames() →获取所有的参数名
Map getParameterMap() →获取存储了所有参数的Map集合
获取客户端信息的方法
String getProtocol() →获取请求的协议
String getRemoteHost() →获取请求的主机名
int getRemotePort() →获取请求的端口
String getRemoteAddr() →获取请求的主机地址
获取服务器信息的方法
String getLocalAddr() →获取服务器的地址
String getLocalName() →获取服务器的主机名
int getLocalPort() →获取服务器的端口号
请求转发方法
RequestDispatcher getRequestDispatcher(String path) →获取请求转发器对象
存取数据的方法
void setAttribute(String name, Object o) →给request域设置属性
Object getAttribute(String name) →从request域中获取属性数据
Enumeration getAttributeNames() →获取request域中的所有属性名
void removeAttribute(String name) →以指定的名字删除惹request域中的属性------| HttpServletRequest 接口
获取请求资源的方法
String getMethod() →获取请求的方式
StringBuffer getRequestURL() →获取请求的URL
String getRequestURI() →获取请求的URI
String getQueryString() →获取URL中的参数列表
获取web应用信息
String getServletPath() →获取Servlet的映射路径
String getContextPath() →获取请求的网站的路径
获取请求头信息
String getHeader(String name) →获取指定名字的请求头
Enumeration getHeaderNames() →获取所有的请求头名字
Enumeration getHeaders(String name) →获取指定名请求头的多个值
long getDateHeader(String name) →获取值为Date类型的请求头
请求获取(重点)
HttpServletRequest接口对象
◆获取单个参数
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 获取一个值的参数
String name = request.getParameter("name");
System.out.println(name);
}
◆获取有多个值的参数
http://localhost:8080/day07/getdata?name=lucy&like=basketball&like=football&like=film public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 获取一个值的参数
String name = request.getParameter("name");
System.out.println(name);
// 获取多个值
String [] likes = request.getParameterValues("like");
System.out.println(Arrays.toString(likes));
}
◆获取所有请求参数
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 获取所有的参数的名字
Enumeration
while(ens.hasMoreElements()){
String par_name = ens.nextElement();
if("name".equals(par_name)){
String par_value = request.getParameter(par_name);
System.out.println(par_name+"="+par_value);
}else{
String [] par_likes = request.getParameterValues("like");
System.out.println(par_name+"="+Arrays.toString(par_likes));
}
}
}
◆获取所有参数对应的Map以及封装(重点)
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 获取所有参数对应的map集合
User user = new User();
Map
// name=jack like=[,,]
Set
for(Iterator
Map.Entry
String entry_key = entry.getKey();
Object entry_value = entry.getValue();
// 进行数据的封装
try {
BeanUtils.setProperty(user, entry_key, entry_value);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(user.getName()+" ,"+Arrays.toString(
user.getLike() ) );
}
◆中文参数的获取(重点)
1、GET请求
浏览器默认会以当前查看页面的解码方式对输入的中文进行编码,一般默认是UTF-8,但是request对象默认是以ISO8859-1进行解码的,由于编码和解码的方式不同,因此导致乱码出现,所以开发者需要对获取的get请求的参数进行重新的正确的解码。
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 处理输出中文
response.setCharacterEncoding("UTF-8"); // 编码
response.setContentType("text/html;charset=UTF-8"); // 解码
// 以下获取的是以ISO8859-1解码的name
String name = request.getParameter("name");
// 获取原始的ISO8859-1中备用字符对应的数字
byte[] iso = name.getBytes("ISO8859-1");
// 重新使用UTF-8进行编码
name = new String(iso,"UTF-8");
// 获取字符流
PrintWriter ps = response.getWriter();
ps.write("name="+name);
}
以上的方式导致开发人员需要额外的编写很多的代码,因此我们需要更简单的方式进行获取get的乱码。
开发者可以使用配置tomcat中的server.xml文件指定tomcat以指定的解码方式获取get请求参数:
connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" /> 因为修改了server.xml文件,必须重启tomcat服务器。 以下的获取的代码中没有额外的处理乱码。 public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { // 处理输出中文 response.setCharacterEncoding("UTF-8"); // 编码 response.setContentType("text/html;charset=UTF-8"); // 解码 String name = request.getParameter("name"); // 获取字符流 PrintWriter ps = response.getWriter(); ps.write("name="+name); } 因为以上的方式需要额外的进行服务器的配置,对于开发人员来讲一般是不可能。因此在实际的项目开发者应该尽量避免使用get方式获取请求参数。 2、POST请求 由于POST请求的参数会默认放置在请求体中,那么也会根据浏览器解析当前页面的解码方式对非ASCII字符进行编码传递,所有在服务器端需要使用语句指定request获取参数的解码方式。 public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { // 指定request对象在post获取参数的时候的解码方式 request.setCharacterEncoding("GB2312"); // 是否要给浏览器输出信息 response.setContentType("text/html;charset=GB2312"); response.setCharacterEncoding("GB2312"); PrintWriter ps = response.getWriter(); // 获取用户的post参数 String name = request.getParameter("name"); ps.write("name="+name); } 总结: 以后获取参数的时候尽量使用post请求,然后在处理请求的方法如doGet()等第一行写如下几条语句: request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); 思考:如果在页面中直接使用一个超链接传递一个中文数据,那么该乱码应该如何处理?(请参见后续的章节) ◆获取客户机信息 http://192.168.10.1:8080/day08/GetInfo?name=jack&gender=male public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter ps = response.getWriter(); // 常见的方法 ps.write("getProtocol():"+request.getProtocol()+" ps.write("getRemoteHost():"+request.getRemoteHost()+" ps.write("getRemotePort():"+request.getRemotePort()+" ps.write("getMethod():"+request.getMethod()+" ps.write("getRequestURL():"+request.getRequestURL()+" ps.write("getRequestURI():"+request.getRequestURI()+" ps.write("getQueryString(): "+request.getQueryString()+" } 运行结果如下: ◆获取服务器信息 http://localhost:8080/day08/GetInfo public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter ps = response.getWriter(); // 常见的方法 ps.write("getLocalAddr():"+request.getLocalAddr()+" ps.write("getLocalName():"+request.getLocalName()+" ps.write("getLocalPort():"+request.getLocalPort()+" } 运行结果如下: 注意:如果使用IP直接访问该链接,那么getLocalName()返回的是null。 ◆获取Web应用信息 http://localhost:8080/day08/GetInfo public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter ps = response.getWriter(); // 常见的方法 ps.write("getServletPath()"+request.getServletPath()+" ps.write("getContextPath()"+request.getContextPath()+" } 运行结果: 注意: 在实际的项目中我们需要不断的进行页面的重定向,但是需要编写重定向的路径,该路径是由项目名+资源名组成的,如果在项目中写死response.sendRedirect("/day08/index.html"); 网站的名字在发布的时候可以任意的进行更改,如果改变的网站的名字,那么原本的编码需要重新指定重定向的路径。因此需要在项目中使用以下代码进行替换: response.sendRedirect(request.getContextPath()+"/index.html"); ◆获取请求头信息 public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { // 判断浏览器是否支持压缩数据的格式 String head = request.getHeader("Accept-Encoding"); System.out.println(head); if(head.contains("gzip")){ ps.write("压缩数据..."); }else{ ps.write("没有压缩的数据..."); } } 注意: getHeaders(String name)该方法获取的是的一个请求头出现的多次值,对于普通的accept请求头不符合该方法的要求。 请求转发 在实际的项目中经常会用到请求转发和请求的重定向技术。 this.getServletContext().getRequestDispatcher("/").forward(request, response); 以上的方式使得请求转发技术实现起来要额外的获取ServletContext对象。因此比较繁琐,所以JavaEE在后期的ServletRequest接口中定义了直接进行请求转发的方法。 public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { request.getRequestDispatcher("/RequestDis2").forward(request, response); } 发现每次进行请求转发的时候,服务器只是创建一次request和response对象,因此我们开发者可以在request对象中添加一些数据传递给请求转发的另一个资源。 可以使用以下两个方法进行请求转发资源之间的数据传输: 设置属性 public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { // 添加request域属性 request.setAttribute("name", "jack"); request.setAttribute("psw", "admin"); request.getRequestDispatcher("/RequestDis2").forward(request, response); } 获取属性 public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter ps = response.getWriter(); ps.write("请求转发"); // 获取request域属性 String name = (String)request.getAttribute("name"); String psw = (String)request.getAttribute("psw"); ps.write("name="+name+" , psw="+psw); } 思考:请求两个servlet在进行请求的重定向的时候是否可以通过request进行传递参数? 解答:不行,因为两次是单独的请求。 请求转发的使用细节 public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter ps = response.getWriter(); // 在请求之前给浏览器做响应 ps.write("请求转发之前"); request.setAttribute("name", "jack"); request.setAttribute("psw", "admin"); request.getRequestDispatcher("/RequestDis2").forward(request, response); } 注意:在请求转发之前如果使用输出流给客户端输出数据,那么该数据不可见。 关闭流强制数据输出给浏览器: public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter ps = response.getWriter(); // 在请求之前给浏览器做响应 ps.write("请求转发之前"); // 强制输出数据给浏览器客户端 ps.close(); request.setAttribute("name", "jack"); request.setAttribute("psw", "admin"); request.getRequestDispatcher("/RequestDis2").forward(request, response); } 注意:一旦请求转发之前使用关闭输出流的方式强制tomcat做出响应(也可以使用flush 方法强制响应),那么控制台错误信息如下: https://www.doczj.com/doc/466160207.html,ng.IllegalStateException: Cannot forward after response has been committed 如果将输出语句放置在请求转发之后 public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter ps = response.getWriter(); request.setAttribute("name", "jack"); request.setAttribute("psw", "admin"); request.getRequestDispatcher("/RequestDis2").forward(request, response); // 请求转发之后输出数据 ps.write("请求转发之后"); } 注意:无论将输出数据的代码写在转发前还是后,只要没有真正输出给浏览器,那么在请求转发之前写的数据都会被Tomcat清空处理。 ◆域对象(重点) 到目前位置我们已经学习了两个对象中可以存储数据,一个是ServletContext一个是ServletRequest。将这些可以用于存储数据的对象称之为域对象。 ServletContext该对象提供的域属性在同一个网站中的所有的servlet均可共享。ServletRequest该对象提供的域属性在同一次请求中或请求转发中数据共享。 ◆RequestDispatcher类 ◆混合类型的数据传输和获取 1、文件数据类型的传输 编写一个用于上传文件数据的表单
");
");
");
");
");
");
");
");
");
");
");
");
查看HTTP协议发现传递的文件的数据格式如下
-----------------------------7dc2bf231c089a
Content-Disposition: form-data; name="file"; filename="readme.txt"
Content-Type: text/plain
helloservlet
-----------------------------7dc2bf231c089a--
使用request.getParameter("file");返回数据为null,无法获取该数据。getParameter("")该方法只能获取application/x-www-form-urlencoded该类型的数据。
思考以上格式的文件数据如何获取出来?
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 获取文件数据
ServletInputStream in = request.getInputStream();
BufferedReader br = new BufferedReader( new
InputStreamReader(in) );
String data = null;
while( (data=br.readLine()) != null ){
System.out.println(data);
}
// 释放资源
br.close();
}
可以使用上述代码将浏览器传递的原始的数据获取并输出。
使用下面的代码可以分别获取文件名和文件的内容
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 获取文件数据
ServletInputStream in = request.getInputStream();
BufferedReader br = new BufferedReader( new InputStreamReader(in) );
String data = null;
// 获取文件名
br.readLine();
String line2 = br.readLine();
line2 = line2.substring(line2.indexOf("filename"));
line2 = line2.split("=")[1];
line2 = line2.substring(1, line2.length()-1);
data = line2;
System.out.println("文件名:"+data);
// 获取文件数据
while((data = br.readLine()) != null ){
if(!data.startsWith("-----------------------------"))
System.out.println("文件内容:"+data);
}
// 释放资源
br.close();
}
2、在表单中既有文件数据又有普通的表单数据。
表单页面
数据格式
-----------------------------7dc33c31c089a
Content-Disposition: form-data; name="file"; filename="readme.txt"
Content-Type: text/plain
helloservlet
-----------------------------7dc33c31c089a
Content-Disposition: form-data; name="author"
jack
-----------------------------7dc33c31c089a--
以上的数据结我们可以写一个基本的程序进行读取,但是通用性可能比较差。因此以后在处理混合类型请求数据的时候必须使用专业的技术。
后面主要学习的文件上传的组件Apache FileUpLoad
后面主要学习的Servlet3.0的新技术。
请求参数的恶意过滤
如果数据是由用户的,那么用户输入的一定是不安全,所以所有的用户输入的数据都要严格经过开发人员的过滤。
以下代码存在隐患
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
// 获取参数
String author = request.getParameter("author");
// 输出参数
PrintWriter out = response.getWriter();
out.write(author);
}
如果用户在输入框中输入如下脚本:
导致浏览器不断打开脚本的窗口直到浏览器崩溃。
因此开发人员每次输出数据给页面的时候都需要严格的进行过滤。
D:\apache-tomcat-6.0.33\webapps\examples\WEB-INF\classes\util\ HTMLFilter.java public static String filter(String message) {
if (message == null)
return (null);
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuffer result = new StringBuffer(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case'<':
result.append("<");
break;
case'>':
result.append(">");
break;
case'&':
result.append("&");
break;
case'"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
Web项目中路径问题
在web网站中会大量的使用到不同的路径,但是为了网站可以更好的移植,那么我们一般在web项目都使用相对路径。所有的相对路径全部以”/”开头。
/在JavaSE项目中对应的class运行的bin目录。
/在JavaEE项目中对应的路径与实际的当前使用者有关系。
如果该路径是给浏览器使用的,那么该/代表Tomcat的webapps目录。
如果该路径是给服务器使用的,那么该/代表当前网站。
举例:区分以下路径到底是给使用?
form的action属性:浏览器使用的,浏览器提交数据。
a超链接的href属性:浏览器使用。
请求转发的路径:服务器使用。
请求重定向:浏览器使用。