# Servlet入门
# 环境部署
常见java相关的web服务器软件有:
- webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
- webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
- JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
- Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源的,免费的。
这里使用Tomcat作为Java服务器。
# 基本操作
这里操作都是windows下的:
- 启动tomcat,运行bin目录下的startup.bat。
- 关闭tomcat,运行bin目录下的shutdown.bat,也可在命令行直接ctrl c。
# 目录结构
# java项目
java项目的目录结构:
-- 项目的根目录
-- WEB-INF目录(WEB-INF目录下的资源不能被浏览器直接访问):
-- web.xml:web项目的核心配置文件
-- classes目录:放置字节码文件的目录
-- lib目录:放置依赖的jar包
# Tomcat目录结构
Tomcat的目录结构:
- bin:主要用来存放tomcat的命令。
- conf:主要用来存放tomcat的一些配置文件。
- server.xml可以设置端口号、设置域名或IP、默认加载的项目、请求编码
- web.xml可以设置tomcat支持的文件类型
- context.xml可以用来配置数据源之类的
- tomcat-users.xml用来配置管理tomcat的用户与权限
- 在Catalina目录下可以设置默认加载的项目
- lib:lib目录主要用来存放tomcat运行需要加载的jar包。
- logs:logs目录用来存放tomcat在运行过程中产生的日志文件。
- windows中是catalina.xxxx-xx-xx.log。
- linux中是catalina.out。
- temp:存放tomcat在运行过程中产生的临时文件。
- webapps:webapps目录用来存放应用程序,当tomcat启动时会去加载webapps目录下的应用程序。可以以文件夹、war包、jar包的形式发布应用。
- work:work目录用来存放tomcat在运行时的编译后文件,例如JSP编译后的文件。清空该目录然后重启tomcat,可达到清除缓存作用。
# 启动问题
- 启动中控制台乱码,找到conf下的logging.properties文件,将其中的encoding = UTF-8的部分全部修改为encoding = GBK。
- 运行时没有JAVA_HOME环境变量。
- 端口被占用。windows下需要找到对应端口并关闭:
- netstat -ano|findstr "端口号"
- tasklist|findstr "PID"
- 在windows任务管理器中关掉对应的进程
# 部署项目
Tomcat中部署项目有三种方式:
- 直接将项目放到webapps目录下即可。也可将项目打成一个war包,再将war包放置到webapps目录下,war包会自动解压缩,删除war包会删除该war包对应的项目。
- 配置conf/server.xml文件,在<Host>标签体中配置<Context docBase="D:\test" path="/testPath" />
- docBase:项目存放的路径
- path:虚拟目录
- 在conf\Catalina\localhost创建任意名称的xml文件,在该文件中写:<Context docBase="D:\test" />,此种方式配置的虚拟目录是xml文件的名称。此种方式是热部署的方式,改变xml能不用重启服务器即可生效。
# IntelliJ配置Tomcat
- Idea会为每一个Tomcat部署的项目单独建立一份配置文件,其所在位置在CATALINA_BASE环境变量中。
- Tomcat真正访问的是它自己部署的web项目,它对应着工作空间中web目录下的所有资源。
# Eclipse配置Tomcat
- 在Window->Preferences->Server->Runtime Environments配置。
- 配置好后在项目右键->Properties->JavaBuildPath->Add Library->Server Runtime->Apache Tomcat v9.0。
- 在Window->Show View->Servers->新增服务器。
注意:
- 如果需要在项目中添加web.xml,可以右击项目,找到Java EE Tools,然后Genertate Deployment Descriptor Stub。
- 在JavaEE项目中添加包依赖,需要添加到/WebContent/WebContent/WEB-INF/lib中,添加到其他目录,即使加到项目属性的JavaBuildPath->Libraries->Classpath中,在Tomcat中运行的时候也会出现NoClassDefFoundError,Tomcat中运行的程序寻找的依赖是JavaBuildPath->Libraries->Classpath->WebAppLibraries中的包,而不是Classpath中的包。
# 常见问题
使用Tomcat10遇到cannot be cast to class jakarta.servlet.Servlet。后来在Apache Tomcat Versions (opens new window)查了下Tomcat版本与servlet兼容性发现Tomcat版本差很多。对于Tomcat 10,官方是这样写的:
Tomcat 10是服务于Jakarta EE9,使用Tomcat 10之前的人需要注意,作为JavaEE向JakartaEE的迁移结果,所有实现API的主要包都从javax.变为jakarta.,当从Tomcat 9 迁移到Tomcat 10时需要代码的改变。
Tomcat启动会在控制台显示乱码问题。在Tomcat配置文件logging.properties中把java.util.logging.ConsoleHandler.encoding = UTF-8改成java.util.logging.ConsoleHandler.encoding = GBK即可。
# Servlet
它是运行在服务器端的小程序,可被看成是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。注意它有两个重要实现:
- GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象。
- HttpServlet:对http协议的一种封装,简化操作。
我们后面使用它可自定义一个类,实现Servlet接口,复写方法,或者直接继承上面的实现类,下面是一个简单的示例,它有如下操作步骤:
- 定义一个servlet。
- 配置servlet。
MyServlet.java文件内容:
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class MyServlet implements Servlet{
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("destroy server");
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
System.out.println("init service");
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("hello world!123456");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
web.xml文件内容:
<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>JavaWebLearn</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-class>MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<url-pattern>/testweb</url-pattern>
</servlet-mapping>
</web-app>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 执行原理
- 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径。
- 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
- 如果有,则在找到对应的<servlet-class>全类名。
- tomcat会将字节码文件加载进内存,并且创建其对象。
- 调用其方法。
# Servlet生命周期
Servlet中有几个方法比较重要:
- init:创建servlet时执行,只执行一次。
- service:每次访问servlet方法时执行一次。
- destroy:销毁servlet时执行,只执行一次。
注意:
- Servlet会在两种情况下被创建,创建时执行init方法,可在web.xml中的<servlet>标签中配置。
- 在servlet第一次被访问时创建。<load-on-startup>的值为负数。
- 在服务器启动时创建。<load-on-startup>的值为0或正整数。
- Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的。
- 多个用户同时访问时,可能存在线程安全问题。
- 尽量不要在Servlet中定义成员变量,即使定义了成员变量,尽量只定义只读成员变量。
- destroy是Servlet被销毁时执行,一般服务器关闭时,Servlet被销毁。
- 只有服务器正常关闭时,才会执行destroy方法。
- destroy方法在Servlet被销毁之前执行,一般用于释放资源。
# 注解
在Servlet 3.0时,可以不创建web.xml,使用WebServlet注解。它的定义如下:
public abstract @interface javax.servlet.annotation.WebServlet extends java.lang.annotation.Annotation {
// Method descriptor #5 ()Ljava/lang/String;
public abstract java.lang.String name() default "";
// Method descriptor #9 ()[Ljava/lang/String;
public abstract java.lang.String[] value() default {};
// Method descriptor #9 ()[Ljava/lang/String;
public abstract java.lang.String[] urlPatterns() default {};
// Method descriptor #12 ()I
public abstract int loadOnStartup() default (int) -1;
// Method descriptor #15 ()[Ljavax/servlet/annotation/WebInitParam;
public abstract javax.servlet.annotation.WebInitParam[] initParams() default {};
// Method descriptor #17 ()Z
public abstract boolean asyncSupported() default false;
// Method descriptor #5 ()Ljava/lang/String;
public abstract java.lang.String smallIcon() default "";
// Method descriptor #5 ()Ljava/lang/String;
public abstract java.lang.String largeIcon() default "";
// Method descriptor #5 ()Ljava/lang/String;
public abstract java.lang.String description() default "";
// Method descriptor #5 ()Ljava/lang/String;
public abstract java.lang.String displayName() default "";
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
注意:
- 上面中的value代表urlPatterns,urlPatterns相当于web.xml中的<url-pattern>。loadOnStartup相当于web.xml中的<load-on-startup>。
- 一个Servlet可以定义多个访问路径:@WebServlet({"/hehe","/hello/world","/*.do"})。
# Request对象
request和response对象是由服务器创建的。request对象是来获取请求消息,response对象是来设置响应消息。
# Request继承结构
request对象继承体系结构:
- ServletRequest(接口)
- HttpServletRequest(接口)
- org.apache.catalina.connector.RequestFacade(实现类)
# Request基本功能
获取请求行数据
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/requestDemo1") public class RequestDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 获取请求方式 :GET String method = request.getMethod(); System.out.println(method); //2.(*)获取虚拟目录: String contextPath = request.getContextPath(); System.out.println(contextPath); //3. 获取Servlet路径: String servletPath = request.getServletPath(); System.out.println(servletPath); //4. 获取get方式请求参数: String queryString = request.getQueryString(); System.out.println(queryString); //5.(*)获取请求URI: String requestURI = request.getRequestURI(); StringBuffer requestURL = request.getRequestURL(); System.out.println(requestURI); System.out.println(requestURL); //6. 获取协议及版本: String protocol = request.getProtocol(); System.out.println(protocol); //7. 获取客户机的IP地址: String remoteAddr = request.getRemoteAddr(); System.out.println(remoteAddr); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40获取请求头数据
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Enumeration; @WebServlet("/requestDemo2") public class RequestDemo2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //演示获取请求头数据 //获取所有请求头名称 Enumeration<String> headerNames = request.getHeaderNames(); //遍历输出这些头信息 while(headerNames.hasMoreElements()){ String name = headerNames.nextElement(); //根据名称获取请求头的值 String value = request.getHeader(name); System.out.println(name+"---"+value); } //获取请求头数据:user-agent String agent = request.getHeader("user-agent"); //判断agent的浏览器版本 if(agent.contains("Chrome")){ //谷歌 System.out.println("谷歌来了..."); }else if(agent.contains("Firefox")){ //火狐 System.out.println("火狐来了..."); } //获取请求头数据:referer String referer = request.getHeader("referer"); System.out.println(referer);//http://localhost/day14/login.html //防盗链 if(referer != null ){ if(referer.contains("/day14")){ //正常访问 // System.out.println("播放电影...."); response.setContentType("text/html;charset=utf-8"); response.getWriter().write("播放电影...."); }else{ //盗链 //System.out.println("想看电影吗?来优酷吧..."); response.setContentType("text/html;charset=utf-8"); response.getWriter().write("想看电影吗?来优酷吧..."); } } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59获取请求体数据,注意只有POST请求方式才有请求体,在请求体中封装了POST请求的请求参数
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; @WebServlet("/requestDemo3") public class RequestDemo3 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取请求消息体--请求参数 //1.获取流对象 //BufferedReader getReader():获取字符输入流,只能操作字符数据 //ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据 //2.再从流对象中拿数据 BufferedReader br = request.getReader(); String line = null; while((line = br.readLine()) != null){ System.out.println(line); } //post 获取请求参数 //根据参数名称获取参数值 String username = request.getParameter("username"); //根据参数名称获取参数值的数组 String[] hobbies = request.getParameterValues("hobby"); for (String hobby : hobbies) { System.out.println(hobby); } //获取所有请求的参数名称 Enumeration<String> parameterNames = request.getParameterNames(); while(parameterNames.hasMoreElements()){ String name = parameterNames.nextElement(); System.out.println(name); String value = request.getParameter(name); System.out.println(value); System.out.println("----------------"); } // 获取所有参数的map集合 Map<String, String[]> parameterMap = request.getParameterMap(); Set<String> keyset = parameterMap.keySet(); for (String name : keyset) { //获取键获取值 String[] values = parameterMap.get(name); System.out.println(name); for (String value : values) { System.out.println(value); } System.out.println("-----------------"); } //获取中文输入参数 //get方式:tomcat 8 已经将get方式乱码问题解决了 //post方式:会乱码,解决办法是在获取参数前,设置request的编码 //1.设置流的编码 request.setCharacterEncoding("utf-8"); //获取请求参数 String username = request.getParameter("username"); System.out.println(username); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# Request扩展功能
请求转发:一种在服务器内部的资源跳转方式
- 步骤:
- 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)。
- 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)。
- 特点:
- 浏览器地址栏路径不发生变化。
- 只能转发到当前服务器内部资源中。
- 转发是一次请求。
- 步骤:
共享数据时就需要使用域对象,它是一个有作用范围的对象,可以在范围内共享数据
- request:代表一次请求的范围,一般用于请求转发的多个资源中共享数据。方法:
- void setAttribute(String name,Object obj):存储数据
- Object getAttitude(String name):通过键获取值
- void removeAttribute(String name):通过键移除键值对
- ServletContext:服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象。这个对象全局唯一,而且工程内部的所有servlet都共享这个对象,所以叫全局应用程序共享对象。
- 获取方式:通过request或者在doPost和doGet内部直接调用getServletContext()。
- request:代表一次请求的范围,一般用于请求转发的多个资源中共享数据。方法:
示例:
请求转发页面:
import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/requestDemo4") public class RequestDemo4 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("demo8888被访问了。。。"); //转发到demo9资源 /* RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo9"); requestDispatcher.forward(request,response); */ //存储数据到request域中 request.setAttribute("msg","hello"); request.getRequestDispatcher("/requestDemo9").forward(request,response); //request.getRequestDispatcher("http://www.itcast.cn").forward(request,response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32被转发的页面:
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/requestDemo5") public class RequestDemo9 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取数据 Object msg = request.getAttribute("msg"); System.out.println(msg); System.out.println("被访问了。。。"); ServletContext servletContext = request.getServletContext(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Response对象
设置响应消息
- 设置响应行
- 格式:HTTP/1.1 200 ok
- 设置状态码:setStatus(int sc)
- 设置响应头:setHeader(String name, String value)
- 设置响应体,使用步骤:
- 获取输出流
- 字符输出流:PrintWriter getWriter()
- 字节输出流:ServletOutputStream getOutputStream()
- 使用输出流,将数据输出到客户端浏览器
- 获取输出流
下面是几个案例。
# 重定向
重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向)。
重定向和转发的区别是:
- 重定向的特点:redirect
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求。不能使用request对象来共享数据
- 转发的特点:forward
- 转发地址栏路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求,可以使用request对象来共享数据
如果只使用html进行重定向:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 方法一:-->
<!-- <meta http-equiv="refresh" content="2;url=http://www.baidu.com"> -->
<title>Title</title>
<script type="text/javascript">
window.onload = function() {
var i = 2;
var tim = document.getElementById("timers");
var timer = setInterval(function() {
if (i == 0) {
//方法二:
window.location.href="http://www.baidu.com";
console.log("清除定时!");
clearInterval(timer);
} else {
tim.innerHTML = i;
--i;
}
}, 1000);
}
</script>
</head>
<body>
<p>您将在 <span class="timeShow" id="timers">3</span> 秒内被重定向到新的地址。</p>
<p>如果超过 3 秒后您仍未跳转,请点击<a href="http://www.baidu.com">百度首页</a></p>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
如果使用servlet来完成重定向是:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 重定向
*/
@WebServlet("/responseDemo1")
public class ResponseDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo1........");
//访问/responseDemo1,会自动跳转到/responseDemo2资源
/* //1. 设置状态码为302
response.setStatus(302);
//2.设置响应头location
response.setHeader("location","/day15/responseDemo2");*/
request.setAttribute("msg","response");
//动态获取虚拟目录
String contextPath = request.getContextPath();
//简单的重定向方法
response.sendRedirect(contextPath+"/responseDemo2");
//response.sendRedirect("http://www.baidu.com");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 服务器返回数据
服务器输出字符数据到浏览器,如果输出中文字符乱码,说明服务器的编码和浏览器的解码不一致,此时需要:
- 设置该流的默认编码
- 告诉浏览器响应体使用的编码
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/responseDemo2") public class ResponseDemo2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取流对象之前,设置流的默认编码:ISO-8859-1 设置为:GBK // response.setCharacterEncoding("utf-8"); //告诉浏览器,服务器发送的消息体数据的编码。建议浏览器使用该编码解码 //response.setHeader("content-type","text/html;charset=utf-8"); //简单的形式,设置编码 response.setContentType("text/html;charset=utf-8"); //1.获取字符输出流 PrintWriter pw = response.getWriter(); //2.输出数据 //pw.write("<h1>hello response</h1>"); pw.write("你好啊啊啊 response"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32服务器输出字节数据到浏览器:
import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/responseDemo3") public class ResponseDemo3 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); //1.获取字节输出流 ServletOutputStream sos = response.getOutputStream(); //2.输出数据 sos.write("你好".getBytes("utf-8")); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 下载文件示例
超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框。我们希望任何资源都必须弹出下载提示框,此时需要使用响应头设置资源的打开方式:
content-disposition:attachment;filename=xxx
下面是一个下载文件的示例:
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取请求参数,文件名称
String filename = request.getParameter("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);//获取文件的mime类型
response.setHeader("content-type",mimeType);
//3.2设置响应头打开方式:content-disposition
//解决中文文件名问题
//1.获取user-agent请求头
String agent = request.getHeader("user-agent");
//2.使用工具类方法编码文件名即可
filename = DownLoadUtils.getFileName(agent, filename);
response.setHeader("content-disposition","attachment;filename="+filename);
//4.将输入流的数据写出到输出流中
ServletOutputStream sos = response.getOutputStream();
byte[] buff = new byte[1024 * 8];
int len = 0;
while((len = fis.read(buff)) != -1){
sos.write(buff,0,len);
}
fis.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
其中DownloadUtils.java为:
import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class DownLoadUtils {
//1. 获取客户端使用的浏览器版本信息
//2. 根据不同的版本信息,设置filename的编码方式不同
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;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# ServletContext对象
该对象代表整个web应用,可用来:
- 获取MIME类型,MIME类型是在互联网通信过程中定义的一种文件数据类型,它的格式:大类型/小类型,比如text/html image/jpeg。要查看Tomcat的MINE类型,可在conf/web.xml查看。
- 可用来共享数据,服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象,该对象全局唯一,而且工程内部的所有servlet都共享这个对象。
- 获取文件的真实(服务器)路径。
示例如下:
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servletContextDemo1")
public class ServletContextDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取
ServletContext context = this.getServletContext();
//ServletContext context1 = request.getServletContext();
//基本使用
String filename = "a.jpg";//image/jpeg
String mimeType = context.getMimeType(filename);
System.out.println(mimeType);
//设置数据
context.setAttribute("info","hello");
// 获取文件的服务器路径
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);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 域对象
Servlet三大域对象的应用 request、session、application(ServletContext)。
- request,一个用户可有多个;
- session,一个用户一个;
- servletContext,所有用户共用一个。ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放,为了节省空间,提高效率,ServletContext中要放必须的、重要的、所有用户需要共享的一些信息。