转载请标明出处:
http://blog.youkuaiyun.com/gj782128729/article/details/52357005;
本文出自:【高境的博客】
1. Servlet简介
1.1. 什么是Servlet
(1) servlet是运行在Web服务器中的小型Java程序。
(2) servlet通常通过HTTP(超文本传输协议)接收和响应来自Web客户端的请求。
1.2. 实现Servlet
(1) 实现Servlet接口
如果实现接口,需要把接口里面的方法都实现。
(2) 继承GenericServlet, HttpServlet类
如果继承类,不需要把类中的方法都实现。
(3) 需要web服务器知道Java程序不是一个普通的java程序,而是一个servlet
通过配置进行操作,在web项目中,web.xml里面进行配置。
1.3. Servlet的入门程序
写一个servlet,实现向页面输出内容hello servlet
第一步,创建一个类,使用这个类继承GenericServlet类;
第二步,实现类里面的service(ServletRequest req,ServletResponse res);
* ServletRequest代表请求
* ServletResponse代表响应
第三步,在Servlet中使用ServletResponse对象向页面输出内容。调用getWriter()方法;
第四步,在web项目中的web.xml进行配置,让服务器知道是一个servlet
<servlet>
<servlet-name>servletDemo1</servlet-name>
<servlet-class>com.gaogao.servlet.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo1</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
2. Servlet的执行过程
(1) 根据在浏览器地址栏输入的地址,找web.xml中相同的url-pattern;
(2) 找到了url-pattern,对应的servlet-name;
(3) 根据找到的servlet-name到另外一个标签里面(servlet)相同名称的servlet-name;
(4) 在servlet标签里面找到了相同名称的servlet-name,找servlet的包类路径servlet-class;
Servlet其实是利用反射原理,让servlet里面的service()方法执行。
3. Servlet的生命周期
servlet的生命周期:从servlet创建到servlet销毁的过程。
在servlet接口里面有五个方法,其中有三个方法是与生命周期相关的方法:
(1) init()方法,在servlet创建时候执行这个方法,执行一次,servlet在第一次访问时候创建。
(2) service()方法,在每次访问servlet时候会执行这个方法,执行多次。
(3) destroy()方法,销毁servlet时候执行这个方法,执行一次。
4. Servlet开发细节的问题
4.1. HttpServletRequest和ServletRequest关系&HttpServletResponse和ServletResponse关系
servletRequest和serlvetResponse不带协议
HttpServletRequest和HttpServletResponse带协议
sun公司设计时候,认为未来互联网的发展有很多的协议,目前只有http协议。
4.2. GenericServlet类两个init方法
查看源码,发现有参数init方法最终也要调用init没有参数的方法,直接使用init没有参数的方法就可以了。
4.3. HttpServlet类里service和doxxx关系
根据提交的方式,调用不同的doXX的方法,比如提交方式是get,调用doGet方法,比如提交方式是post,调用doPost方法;
一般在开发中,直接写doGet和doPost方法就可以了;
一般在创建servlet时候,直接继承HttpServlet实现servlet。
4.4. 服务器启动时候创建servlet
通过配置文件进行配置,在servlet标签里面写标签:
<load-on-startup>正整数的值</load-on-startup>
4.5. 简化编程
当通过get提交方式时候,实现从1加到100;
当通过post提交方式时候,实现从1加到100;
无论什么提交方式,代码都能执行到,在dopost方法里面调用doget方法。
5. url-pattern的配置
5.1. 配置有三种方式
第一种方式:完全路径匹配,写法 :/aa
,/hello
第二种方式:目录匹配,写法:/aa/*
第三种方式:扩展名匹配,写法: *.do
, *.action
5.2. 优先级
完全路径匹配 > 目录匹配 > 扩展名匹配
5.3. 练习
对于如下的一些映射关系:
Servlet1 映射到 /abc/*
Servlet2 映射到/*
Servlet3 映射到 /abc
Servlet4 映射到 *.do
问题:
1、当请求URL为"/abc/a.html"
,"/abc/*"
和"/*"
都匹配,哪个servlet响应?
Servlet1
2、当请求URL为"/abc"
时,"/abc/*"
和"/abc"
都匹配,哪个servlet响应?
Servlet3
3、当请求URL为"/abc/a.do"
时,"/abc/*"
和"*.do"
都匹配,哪个servlet响应?
Servlet1
4、当请求URL为"/a.do"
时,"/*"
和"*.do"
都匹配,哪个servlet响应?
Servlet2
5、当请求URL为"/xxx/yyy/a.do"
时,"/*"
和"*.do"
都匹配,哪个servlet响应?
Servlet2
6. 开发中路径的问题
6.1. 相对路径
在html文件中引入图片:
第一种:图片和html在同一个目录下面,直接写图片的名称
第二种:图片在html的上层目录, 写 ../ 表示上层目录
第三种:图片在html的下层目录, 直接写目录名称和图片名称
6.2. 绝对路径(一般开发中都使用)
第一种写法:http://ip地址+端口号/文件的路径
<img src="http://127.0.0.1/day07-3/path02/a.jpg"/>
第二种写法:直接写 /项目名称/文件路径
<img src="/day07-3/path01/cc/c.jpg"/>
7. 请求重定向和请求转发
7.1. 请求重定向
(1) 使用的是客户端路径
(2) 重定向请求两次,使用的是客户端路径,携带项目名称,比如/day07/demo3
请求重定向可以使用一下两种方式:
a) 设置状态码302+头信息Location实现重定向操作
b) 使用response.sendRedirect()实现重定向操作
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {
//得到输入的用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
//根据用户名和密码判断,(用户名admin、密码123456),判断正确则向页面输出login success内容
if("admin".equals(username) && "123456".equals(password)) {
//向页面输出内容
response.getWriter().write("login success");
} else {
//重定向到登录页面
//设置状态码
// response.setStatus(302);
//使用头Location完成重定向
// response.setHeader("Location", "/day08-1/login.html");
//简写方式
response.sendRedirect("/day08-1/login.html");
}
}
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
定时跳转的案例
public class RefreshServlet extends HttpServlet {
/**
* 定时跳转
*/
public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {
//使用头信息Refresh实现,表示5秒后跳转到指定的url路径
response.setHeader("Refresh", "5;url=/day08-1/login.html");
//提示
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("将在5秒之后跳转到登录页面");
}
public void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {
doGet(request, response);
}
}
7.2. 请求转发
(1) 使用的是服务端路径
(2) 转发请求一次,使用的是服务器端路径,不需要携带项目名称,比如/demo4
示例代码:
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {
//获取表单提交的用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
//判断 用户名 admin,密码 123456
if("admin".equals(username) && "123456".equals(password)) {
//登录成功
response.getWriter().write("login success");
} else {
//登录失败,给request设置域属性msg,并且转发到登录页面,并且将错误信息传递过去
request.setAttribute("msg", "用户名或者密码错误");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
doGet(request, response);
}
}
8. ServletConfig对象
8.1. 获取ServletConfig对象
直接使用方法创建对象getServletConfig()。
8.2. 得到当前运行的servlet的名称
(1)web.xml中<servlet-name>ConfigDemo1</servlet-name>
(2)String getServletName()
8.3. 创建servletContext对象
(1)ServletContext getServletContext()
(2)一般都使用getServletContext()方法
8.4. 获取初始化参数
(1)在web.xml中进行配置初始化参数
在servlet标签里面进行配置
(2)String getInitParameter(String name) :根据名称得到值(参数是初始化参数名称)
代码:
//得到servletconfig对象
ServletConfig config = getServletConfig();
//getInitParameter(String name)
String username = config.getInitParameter("username");
String password = config.getInitParameter("password");
(3)Enumeration getInitParameterNames() :得到所有的初始化参数的名称
代码:
//得到servletconfig对象
ServletConfig config = getServletConfig();
//得到所有的初始化参数名称
Enumeration<String> enumrEnumeration =config.getInitParameterNames();
//得到每个参数的名称
while(enumrEnumeration.hasMoreElements()) {
String name = enumrEnumeration.nextElement();
//根据name得到值
String value = config.getInitParameter(name);
System.out.println(name+" :: "+value);
}
9. ServletContext对象
9.1. 创建ServletContext对象
第一种方式,使用ServletConfig对象里面的方法 getServletContext()
第二种方式,直接使用 getServletContext()
9.2. 获取全局的初始化参数
(1)配置全局初始化参数
<context-param>
<param-name>url</param-name>
<param-value>localhost</param-value>
</context-param>
(2)String getInitParameter(String name),根据名称得到全局初始化参数的值:
//得到servletContext对象
ServletContext context = getServletContext();
//根据名称得到全局初始化参数的值
String url = context.getInitParameter("url");
String name = context.getInitParameter("name");
(3)Enumeration getInitParameterNames(),得到所有的全局初始化参数的名称:
//得到servletContext对象
ServletContext context = getServletContext();
//使用方法得到所有的全局初始化参数的名称
Enumeration<String> enumrEnumeration = context.getInitParameterNames();
//得到每个全局初始化参数的名称
while(enumrEnumeration.hasMoreElements()) {
String name = enumrEnumeration.nextElement();
String value = context.getInitParameter(name);
System.out.println(name+" :: "+value);
}
9.3. servletContext域对象
在启动tomcat服务器时候,会为每个项目创建一个servletContext对象,在这个项目里面如果通过servlet1向servletContext里面设置一个值,在这个项目里面的其他的servlet里面都可以获得这个值。
(1)servletContext域对象:在一定的范围内,存值和取值,范围是整个web项目
(2)存值:setAttribute(String name, Object object)
(3)取值:getAttribute(String name)
(4)首先创建servlet1,通过servlet1向servletContext里面设置一个值,其次,再创建servlet2,在servlet2获取通过servlet1设置的值
9.4. 练习:统计网站的访问次数
创建一个servlet,每次访问这个servlet计算一次访问
实现的步骤(分析图)
10. ServletContext获取项目资源
10.1. 传统方式获取web项目中的文件
(1)创建web项目,创建properties文件
(2)得到要操作文件的输入流,使用相对路径
* classes/db1.properties : 相对路径
* 相对虚拟机的位置
* 在web项目中,虚拟机在tomcat启动时候,tomcat在bin里面
(3)使用传统方式里面的相对路径,不能读取web项目中的文件
10.2. ServletContext读取项目中的文件
(1)InputStream getResourceAsStream(java.lang.String path),得到要操作文件的输入流
(a)第一个操作:文件放到src下面
路径:第一个位置/,理解为项目的名称;后面写文件在tomcat的webapps里面的具体的路径
代码:
InputStream in = context.getResourceAsStream("/WEB-INF/classes/db1.properties");
(b)第二个操作:文件放到包里面
路径:第一个位置/理解为项目名称;后面写文件在tomcat的webapps下面的具体的路径
InputStream in= context.getResourceAsStream
("/WEB-INF/classes/cn/itcast/read/db2.properties");
(c)第三个操作:文件放到webroot下面
路径:第一个位置/理解为项目名称;后面写文件在tomcat的webapps下面的具体的路径
代码:
InputStream in = context.getResourceAsStream("/db3.properties");
*注意:当把文件放到和webroot同级的目录下面,这个文件不会部署到tomcat里面,所以使用servletContext对里面getResourceAsStream方法不能得到文件的内容。
(2)String getRealPath(java.lang.String path),得到要操作文件的完全路径(带盘符的路径)
参数:和getResourceAsStream类似的
第一个位置/,项目名称;后面写文件在tomcat的webapps里面的具体的路径。
代码:
//使用getRealPath方法
String path = context.getRealPath("/db3.properties");
//C:\Users\asus\Desktop\javaweb\day06\apache-tomcat-7.0.53\webapps\day07-7\db3.properties
//得到要操作文件的输入流
InputStream in = new FileInputStream(path);
11. 类加载器读取文件
读取的文件的位置是 classes里面的文件
得到类加载器:
(1)首先得到Class
*第一种方式:类名.class
*第二种方式:对象.getClass()
*第三种方式:Class.forName(“包类路径”)
(2)使用Class得到类加载器
代码:
//得到类的Class
Class clazz = ServletDemo1.class;
//得到类加载器
ClassLoader loader = clazz.getClassLoader();
//得到要操作文件的输入流
//文件的路径,因为读取的classes里面的文件,直接写文件的名称
InputStream in = loader.getResourceAsStream("db1.properties");
12. 默认的servlet
比如在浏览器的地址栏随便输入一个地址,出现404,资源找不到,这个效果是由默认的servlet实现的。在tomcat的conf里面找到web.xml,有对默认servlet的配置:
(a)如果自己创建servlet,让这个servlet在启动时候创建,<load-on-startup>大于1的值</load-on-startup>
(b)默认servlet的配置里面url-pattern是/,当把自己创建的servlet的url-pattern写成/,这个servlet就会成为一个默认的servlet
<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-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
在默认的servlet的初始化参数里面有 listings,当把这个参数的值设置成true之后,当直接访问web项目中文件夹时候,会把文件夹里面的所有内容显示出来。
13. Response和Request
request:代表请求,在浏览器的地址栏输入地址,点击回车,这个过程称为一次请求;
response:代表响应,服务器端根据客户端的请求,返回数据到浏览器中进行显示,这个过程称为一次响应。
14. Response对象
HttpServletResponse,是一个接口,父接口是ServletResponse,代表响应对象。
http的响应包含三部分组成:
(1)第一部分:响应行,响应行中包含了状态码
常用方法:
方法 | 作用 |
---|---|
setStatus(int sc) | 设置状态码 如response.setStatus(302) |
(2)第二部分:响应头
响应头是key-value结构,一个key可以有一个value,一个key也可以有多个value。
常用方法:
方法 | 作用 |
---|---|
setHeader(java.lang.String name, java.lang.String value) | 设置响应头 两个参数:第一个参数是响应名称;第二个参数值 |
setIntHeader(java.lang.String name, int value) | 针对int类型值的方法 |
setDateHeader(java.lang.String name, long date) | 值long类型,是毫秒数(1970 1 1至今的毫秒数) |
addHeader(java.lang.String name, java.lang.String value) | 设置响应头 两个参数:第一个参数是响应名称;第二个参数值 |
addIntHeader(java.lang.String name, int value) | 针对int类型值的方法 |
addDateHeader(java.lang.String name, long date) | 值long类型,是毫秒数 |
setHeader和addHeader的区别:
setHeader会将之前的值覆盖掉,而addHeader可以添加多个响应头。
(3)第三部分:响应体,向页面显示的内容
常用方法:
方法 | 作用 |
---|---|
getWriter() | 使用字符流向页面输出内容 |
getOutputStream() | 使用字节流向页面输出内容 |
14.1. 重定向的案例
当注册一个网站,注册完成之后,5秒之后跳转到登录页面。
实现方式:使用头信息Refresh实现
response.setHeader("Refresh","在几秒值后跳转;url=要跳转到页面的路径");
创建servlet,在servlet实现,在五秒之后跳转到一个页面:
response.setHeader("Refresh", "5;url=/day08-1/login.html");
14.2. 设置响应体(向页面输出内容)
14.2.1. 使用字节流向页面输出内容
代码:
response.getOutputStream().write("输出的内容".getBytes());
如果向页面输出中文,根据不同的浏览器的编码设置会产生乱码问题。产生原因:浏览器的编码和字节数组的编码不一致。
解决方法:让浏览器的编码和字节数组的编码一致
1、设置浏览器的编码
2、设置字节数组的编码
//设置浏览器的编码 使用头信息 Content-Type
response.setHeader("Content-Type", "text/html;charset=utf-8");
//设置字节数组的编码
response.getOutputStream().write("字节流中文".getBytes("utf-8"));
14.2.2. 使用字符流向页面输出内容
代码:
response.getWriter().write("response");
如果使用字符流向页面输出中文,一定会有乱码
原因:使用字符流向页面输出内容;首先会把内容放到response缓冲区里面,response缓冲区默认的编码是 iso8859-1,这个编码不支持中文,一定会有乱码。
解决方法:response缓冲区的编码和浏览器的编码一致。
1、设置response缓冲区的编码
2、设置浏览器的编码
//设置response缓冲区的编码
response.setCharacterEncoding("utf-8");
//设置浏览器的编码
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.getWriter().write("字符流中文");
14.3. response的流的注意事项
(1)使用字符流向页面输出中文乱码问题解决,简写方式
response.setContentType("text/html;charset=utf-8");
(2)字节流和字符流是互斥的
(3)使用字符流不能直接向页面输出数字
//根据数字到码表中查询数字对应的字符,把字符输出
response.setCharacterEncoding("utf-8");
response.getWriter().write(111);
15. 文件下载的案例
(1) 设置头信息 Content-Disposition,无论是什么格式的文件都以下载方式打开
(2) 在服务器上面有一个可以下载的文件
(3) 从服务器上拿到这个文件(使用文件输入流得到文件)
(4) 使用输出流把文件写到浏览器
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 得到要下载文件的路径
String path = getServletContext().getRealPath("/down/a.zip");
// 得到文件的名称
int lens = path.lastIndexOf("\\");
String filename = path.substring(lens + 1);
// 设置头信息
response.setHeader("Content-Disposition","attachment;filename=" + filename);
// 得到文件的输入流
InputStream in = new FileInputStream(path);
// 使用输出流操作
OutputStream out = response.getOutputStream();
// 流对接
int len = 0;
byte[] b = new byte[1024];
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
// 关闭流
in.close();
}
16. Request对象
request代表请求的对象,HttpServletRequest接口,父接口是ServletRequest。
16.1. 获取请求行的信息
方法 | 作用 |
---|---|
getMethod() | 得到http请求方式 |
getRequestURI() | 得到请求地址(不包含ip+端口号) |
getProtocol() | 得到http的版本 |
16.2. 获取请求头的信息
方法 | 作用 |
---|---|
getHeader(java.lang.String name) | 根据名称得到请求头的值,如:头信息 User-Agent:获取当前请求的浏览器的类型 String agent = request.getHeader(“User-Agent”); |
16.3. 获取客户机的信息
方法 | 作用 |
---|---|
getContextPath() | 请求项目的名称 |
getRequestURL() | 客户端发送的请求的路径 |
getRemoteAddr() | 获取当前客户端的ip地址 |
16.4. 获取表单提交的数据
(1)String getParameter(java.lang.String name) :参数是表单输入项name属性的值,根据名称得到输入的值
代码:
String username = request.getParameter("username");
String password = request.getParameter("password");
(2)String[] getParameterValues(java.lang.String name) :参数是表单输入项name的值,针对复选框的情况
代码:
String[] loves = request.getParameterValues("love");
(3)String[] getParameterValues(java.lang.String name) :
返回的是map集合,key是表单输入项name属性的值,value是输入的值
代码:
Map<String,String[]> map = request.getParameterMap();
//得到map集合里面的key和value,遍历map
Set<String> keys = map.keySet();
//遍历set集合
for (String key : keys) {
//根据key得到value
String[] values = map.get(key);
//key和对应的value输出(表单输入项name的属性值和输入的值)
System.out.println(key+" :: "+Arrays.toString(values));
}
(4)Enumeration
16.5. 获取表单提交的中文数据乱码问题
(1)post提交方式解决方法
使用post提交数据时候,会把数据放到request缓冲区里面,request缓冲区默认的编码 iso8859-1,不支持中文。
解决方法:
设置request缓冲区的编码
代码:
request.setCharacterEncoding("utf-8");
(2)get提交中文乱码解决
有三种方式
第一种:修改tomcat的配置文件
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="utf-8"/>
第二种:把数据先编码,再进行解码
第三种:使用string构造进行编码,new String(“”);
代码:
username = new String(username.getBytes("iso8859-1"),"utf-8");
16.6. request是域对象
(1) 域对象:在一定的范围内,可以存值和取值。
(2) servletContext域对象:范围是整个web项目,存值setAttribute方法和取值getAttribute方法。
(3) request也是一个域对象:范围是一次请求,存值和取值。
向request域里面存值的方法:setAttribute(java.lang.String name, java.lang.Object o);
从request域里面取值的方法:getAttribute(java.lang.String name)。
(4) request域对象范围是一次请求,经常和转发一起使用
代码request.getRequestDispatcher(“转发的路径不带项目名称”).forward(..);
(5) 举例演示request域对象
创建servlet1,在servlet1里面向request域里面设置一个值,最后转发到servlet2里面:
//向request域里面设置一个值
request.setAttribute("msg", "itcast100");
//转发到servlet2
request.getRequestDispatcher("/servlet2").forward(request, response);
创建servlet2,在servlet2里面获取通过servlet1向request域里面设置的那个值
//获取通过servlet1向request里面设置的值
response.getWriter().write(""+request.getAttribute("msg"));
16.7. 重定向和转发的区别
(1)重定向
请求次数:重定向请求两次,请求的地址带项目名称
实现方式:302+Location实现重定向的操作
实现代码:response.sendRedirect(“路径 带项目名称”);
(2)转发
请求次数:转发请求一次,路径不需要带项目名称(在服务器内部进行操作)
实现代码:request.getRequestDispatcher(“转发的路径 不带项目名称”).forward(request, response);
(3)重定向:从一个网站到另外的一个网站
转发:请求的过程中需要携带数据操作
17. 文件上传
17.1. 什么是文件上传
把本地的文件存储到服务器上,这个过程称为文件的上传。比如,网盘、qq空间。
17.2. 文件上传的实现
(1) jspSmartUpload:应用在jsp的模型一
适于嵌入执行上传下载操作的JSP文件中
(2) fileUpload:应用在jsp的模型二(mvc)
FileUpload 是 Apache commons下面的一个子项目
组件FileUpload依赖于Commons IO组件
导入jar包(有两个jar包)
(3) 要想使用第三方的技术实现文件的上传,首先导入jar包
17.3. 文件上传需要满足的条件
第一个要求:表单,提交方式是post
get提交方式:地址栏会携带数据,get大小有限制
第二个要求:在表单里面有文件上传项,必须有name属性
第三个要求:在form里面,设置一个属性值enctype,设置为multipart/form-data
18. 文件上传的原理的分析(画图)
首先,找到分割线;
第二,根据分割线区别不同的项;
第三,普通输入项得到值;
第四,文件上传项,得到文件的内容,把内容写到服务器里面的一个文件中(使用输入流得到文件的上传内容,使用输出流把文件内的内容写到服务器上)
19. 代码实现文件上传
19.1. 文件上传代码实现的步骤
第一步:创建磁盘文件项工厂
new DiskFileItemFactory();
第二步:创建核心上传类
new ServletFileUpload(FileItemFactory fileItemFactory);
第三步:使用核心上传类解析request对象
parseRequest(javax.servlet.http.HttpServletRequest request)
返回的List集合,集合里面有多个FileItem,List<FileItem>
第四步:遍历list集合,得到每个FileItem
第五步:判断是普通输入项还是文件上传项
boolean isFormField()
第六步:如果是普通输入项得到值;如果是文件上传项编写上传的代码
普输入项:
getFieldName():得到普通输入项name的属性的值
getString():得到普通输入项里面输入的值
文件上传项:
得到通过表单提交过了的文件的输入流,getInputStream()
创建输出流,把文件的输入流写到服务器的一个文件中。
19.2. 代码实现
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// 创建磁盘文件项工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置缓冲区大小和临时文件路径
factory.setSizeThreshold(1 * 1024 * 1024); // 字节
String temp = getServletContext().getRealPath("/temp");
factory.setRepository(new File(temp));
// 创建核心上传类
ServletFileUpload fileUpload = new ServletFileUpload(factory);
// 设置上传文件名的编码
fileUpload.setHeaderEncoding("utf-8");
// 设置上传文件的大小
// fileUpload.setFileSizeMax(1*1024*1024); //字节
// 解析request对象
List<FileItem> list = fileUpload.parseRequest(request);
// 遍历list集合
for (FileItem fileItem : list) {
// 判断普通输入项
if (fileItem.isFormField()) {
// 得到普通输入项的name的属性值和输入的值
String name = fileItem.getFieldName();
String value = fileItem.getString("utf-8");
System.out.println(name + " :: " + value);
} else {
// 得到上传文件的名称 getName()
// 在某些浏览器里面,得到的是全路径名称 c:\aa\1.txt
String filename = fileItem.getName();
// 判断是否带 \,如果带 \进行截取
int lens = filename.lastIndexOf("\\");
if (lens != -1) {
// 截取
filename = filename.substring(lens + 1);
}
// 在文件名称里面添加随机的唯一的值
String uuid = UUID.randomUUID().toString();
// uuid_filename
filename = uuid + "_" + filename;
// 得到提交的文件的输入流
InputStream in = fileItem.getInputStream();
// 得到文件夹的带盘符的路径 ,servletContext对象
String path = getServletContext().getRealPath("/upload");
// 创建输出流
OutputStream out = new FileOutputStream(path + "/" + filename);
// 流对接
int len = 0;
byte[] b = new byte[1024];
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
in.close();
out.close();
// 删除临时文件
fileItem.delete();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
20. 核心api的使用
DiskFileItemFactory(int sizeThreshold, java.io.File repository)
有两个参数:
第一个参数设置上传文件的缓冲区的大小;
第二个参数是如果上传文件超出了缓冲区,产生临时文件,设置临时文件路径。
DiskFileItemFactory()
setSizeThreshold(int sizeThreshold):设置上传文件的缓冲区的大小
setRepository(java.io.File repository):设置临时文件路径
20.2. ServletFileUpload
ServletFileUpload(FileItemFactory fileItemFactory)
方法 | 解释 |
---|---|
parseRequest(javax.servlet.http.HttpServletRequest request) | 解析request对象,返回List集合,集合里面每个部分是FileItem。 |
setHeaderEncoding(java.lang.String encoding) | 设置上传文件名称的编码 |
setFileSizeMax(long fileSizeMax) | 设置单个上传文件的大小 |
setSizeMax(long sizeMax) | 设置上传文件的总大小 |
20.3. FileItem:文件项
方法 | 解释 |
---|---|
boolean isFormField() | 判断是否是普通输入项,返回boolean,如果返回true是普通输入项 |
getFieldName() | 得到普通输入项name的属性值 |
getString() | 得到普通输入项输入的值 |
getString(java.lang.String encoding) | 输入的值有中文,设置编码 |
getName() | 得到上传文件的名称。在某些浏览器里面得到带路径的名称,截取操作 |
getInputStream() | 得到表单提交的文件的输入流 |
delete() | 删除临时文件 |
21. 文件上传问题的解决
文件重名的问题:如果上传了多个项目名称的文件,最后一次上传的文件,把之后的文件给覆盖了。
解决方法:在上传的文件名称前面,添加一个随机的唯一的字符串,保证每个文件名称都是唯一的一个值:
第一种方式:使用当前时间毫秒数实现
第二种方式:使用UUID工具类实现
代码:
//在文件名称里面添加随机的唯一的值
String uuid = UUID.randomUUID().toString();
//uuid_filename
filename = uuid+"_"+filename;