Servlet:server applet
-
概念:运行在服务器端的小程序
- Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则
- 将来我们自定义一个类,实现Servlet接口,复写方法
-
快速入门
-
创建JavaEE项目,定义一个类实现Servlet接口,实现抽象方法,配置Servlet
-
配置servlet
<!--配置servlet--> <servlet> <servlet-name>demo1</servlet-name> <servlet-class>cn.ycl.servlet.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>demo1</servlet-name> <url-pattern>/demo1</url-pattern> </servlet-mapping>
-
执行原理
- 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
- 查找web.xml文件,是否有对应的标签体内容
- 如果有,则在找到对应的全类名
- tomcat会将字节码文件加载进内存,并且创建其对象
- 调用其方法
-
Servlet中的生命周期方法
-
被创建:执行init方法,只执行一次
-
Servlet什么时候被创建?
-
默认情况下,第一次被访问时,Servlet被创建
-
可以配置执行Servlet的创建时机
-
在标签下配置
1. 第一次被访问时,创建 * <load-on-startup>的值为负数 2. 在服务器启动时,创建 * <load-on-startup>的值为0或正整数
-
-
-
Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
- 多个用户同时访问时,可能存在线程安全问题
- 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值
-
-
提供服务:执行service方法,执行多次
- 每次访问Servlet时,Service方法都会被调用一次。
-
被销毁:执行destroy方法,只执行一次
- Servlet被销毁时执行。服务器关闭时,Servlet被销毁
- 只有服务器正常关闭时,才会执行destroy方法
- destroy方法在Servlet被销毁之前执行,一般用于释放资源
Servlet3.0:注解配置
- 好处:支持注解配置。可以不需要web.xml了
- 步骤:
- 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
- 定义一个类,实现Servlet接口
- 复写方法
- 在类上使用@WebServlet注解,进行配置
- @WebServlet(“资源路径”)
- Servlet相关配置
- urlpartten:Servlet访问路径
- 一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})
- 路径定义规则:
- /xxx:路径匹配
- /xxx/xxx:多层路径,目录结构
- *.do:扩展名匹配
- urlpartten:Servlet访问路径
Servlet的体系结构
Servlet – 接口
|
GenericServlet – 抽象类
|
HttpServlet – 抽象类
- GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
- 将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可
- HttpServlet:对http协议的一种封装,简化操作(推荐)
- 定义类继承HttpServlet
- 复写doGet/doPost方法
ServletContext对象
-
概念:代表整个web应用,可以和程序的容器(服务器)来通信
-
获取:
-
通过request对象获取
request.getServletContext();
-
通过HttpServlet获取
this.getServletContext();
-
-
功能:
-
获取MIME类型:在互联网通信过程中定义的一种文件数据类型
- 格式: 大类型/小类型 text/html image/jpeg
- 获取:String getMimeType(String file)
-
域对象:共享数据
- setAttribute(String name,Object value)
- getAttribute(String name)
- removeAttribute(String name)
- ServletContext对象范围:所有用户所有请求的数据
-
获取文件的真实(服务器)路径
- 方法:String getRealPath(String path)
String b = context.getRealPath("/b.txt");//web目录下资源访问 System.out.println(b); String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问 System.out.println(c); String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问 System.out.println(a);
-
案例
文件下载需求:
- 页面显示超链接
- 点击超链接后弹出下载提示框
- 完成图片文件下载
步骤:
-
定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
-
定义Servlet
-
获取文件名称
-
使用字节输入流加载文件进内存
-
指定response的响应头:
content-disposition:attachment;filename=xxx
-
将数据写出到response输出流
-
-
中文文件问题
解决思路:
- 获取客户端使用的浏览器版本信息
- 根据不同的版本信息,设置filename的编码方式不同
-
代码实现
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求参数,文件名称
String filename = req.getParameter("filename");
System.out.println(filename);
//2.使用字节输入流加载文件进内存
//2.1找到文件服务器存储路径
ServletContext servletContext = this.getServletContext();
String realPath = servletContext.getRealPath("/img/" +filename);
//2.2用字节流关联
FileInputStream fis = new FileInputStream(realPath);
//3.设置response的响应头
//3.1设置响应头类型:content-type
String mimeType = servletContext.getMimeType(filename);//获取文件的mine类型
resp.setHeader("content-type",mimeType);
//3.2设置响应头打开方式:content-disposition
//解决中文文件名问题
//1.获取user-agent
String header = req.getHeader("user-agent");
//2.使用工具类编码文件名
filename = DownLoadUtils.getFileName(header, filename);
resp.setHeader("content-disposition","attachment;filename="+filename);
//4.将输入流的数据写到输出流中
ServletOutputStream sos = resp.getOutputStream();
byte[] buff = new byte[1024*8];
int len = 0;
while ((len = fis.read(buff)) != -1){
sos.write(buff,0,len);
}
fis.close();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}
public class DownLoadUtils {
public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}