[TOC]
Servlet基础入门学习1
|[TOC]
0x01 快速入门
描述:在进行JavaWeb开发学习的时候必不可少就是Tomcat Web 容器服务器,因为它开源免费、便于上手,并且使用安装简单。
简单介绍:
Tomcat是一款开源软件、免费的Web容器软件,由Apache基金会旗下采用JAVA进行开发,Tomcat是一款Web容器自身不能作为负载均衡的软件;
主要应用于发布网页代码,提供网页信息服务,用户通过浏览可以实现界面的访问;Tomcat默认可以处理静态的网页,也可以处理动态的网页;
在这里我们就详细演示安装流程了,在我其他的Tomcat运维文章中有它的详细以及优化配置等.
学习环境准备:
- Java的JDK8(并且配置好环境变量)
- Tomcat 7.0.100 : http://tomcat.apache.org/download-70.cgi
- Eclipse IDE
Tomcat 7.0目录结构说明1
2
3
4
5
6
7* bin:Tomcat 启用binary以及一些启动jar包
* conf:Tomcat配置文档
* lib:Tomcat运行所依赖的jar文件
* logs:运行过程中的日志文件
* temp:临时文件
* webapps:项目发布的目录,以及war解压的目录;
* work:JSPbuild成为java文件的临时存放地
0x02 项目发布
描述:如何将项目发布到Tomcat中运行?
方式1:移动项目到Webapps目录(使用较多)
描述:冷部署可以直接将项目文件夹拖入Webapps目录之中并需要重新启动Tomcat;1
2
3
4#Tomcat控制台提示
# 信息: 把web 应用程序部署到目录 [W:\apache-tomcat-7.0.100\webapps\Demo1]
# 二月 15, 2020 10:40:11 下午 org.apache.catalina.util.SessionIdGeneratorBase crea
# eSecureRandom
方式2:Host配置虚拟路径
描述:通过在Conf/Server.xml配置文件中HOST元素接地添加上<Content>
属性 130 行左右;该方式的区别不同于第一种是在于它不会在Tomcat控制终端日志中显示。
1 | <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> |
参考地址:http://127.0.0.1:8080/docs/config/context.html#Defining_a_context
访问地址效果如上面图显示一致:http://127.0.0.1:8080/Demo2/index.xml
方式3:Engine配置虚拟路径
描述:与方式2大致相同不同的是进行加载的目录不同而已依赖于Engine进行单独的上下文元素可将Context元素复制到引擎文件中即可;
1 | #$CATALINA_BASE/conf/[enginename]/[hostname]/ |
根据上面的分析可以总结出Tomcat主要包含了 2 个核心组件:连接器(Connector)
和容器(Container)
,
- 1.一个Tomcat是一个Server,
- 2.而一个Server下有多个Service,也就是我们部署的多个应用,一个应用下有多个连接器(Connector)和一个容器(Container)容器下有多个子容器;
- 3.Engine下有多个Host子容器,Host下有多个Context子容器,Context下有多个Wrapper子容器。
0x03 项目打包
描述:在实际的开发中我们需要将我们的web工程打压成为war包或者jar包进行tomcat部署或者在jvm虚拟机中运行;
问:如何将项目打包成为jar?
- 1.右键工程选择
Export
选择other在java目录下选择jar;
- 2.进行导出jar配置一般默认就行;
0x04 Servlet基础
描述:Servlet[ /ˈsɜːvlɪt/ ]
API 是运行在Tomcat Web服务器容器中的小型Java程序伺服小程式;小服务程
,通过HTTP(超文本传输协议)接收和响应来自Web客户端的请求;更多的是配合动态资源做项目,当然也可以使用到Servlet只不过在Tomcat里面已经定义了一个DefaultServlet;
1.Hello World
描述:在上面Tomcat安装好后它给我们提供了一个示例页面,进行使用和学习 Servlet ( Servlet Examples with Code ) ;
地址: http://127.0.0.1:8080/examples/servlets/
静态项目创建流程:
- 1.采用Eclipse建立一个Web工程,首先切换到
Java EE
视图,然后选择Server选项卡并且配置好Tomcat服务器;
- 2.选择完成的Tomcat 7 Server 进行最后一步配置Web项目存放到新建立的wtpWebapps目录中保存即可,即
D:\apache-tomcat-7.0.100\wtpwebapps
;
- 3.新建一个动态的Web工程(Dynamic Web Project),设置项目名称为HelloWorld;
- 4.测试一个Web工程,在WebContent目录中建立一个静态资源index.html来测试应用服务器,选择项目进行Run on Server也可以快捷键
ALT+SHIFT+X,R
,第一次运行按照提示即可发布;
访问地址:http://localhost:8080/HelloWorld/
注释:实际上是采用上面部署的第二种方法,在Server.xml中添加了一句<Context docBase="D:\apache-tomcat-7.0.100\wtpwebapps\HelloWorld" path="/HelloWorld" reloadable="true" source="org.eclipse.jst.jee.server:HelloWorld"/>
Servelet项目创建流程:
- 5.在项目的JAVA Resource中的src中创建一个测试Servlet的pakeage,并且建立一个java文件实现Servlet;
/HelloWorld/src/cn/weiyigeek/servlet/HelloWorld.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package cn.weiyigeek.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @author Administrator
* 说明:测试验证Servlet
*/
// 1.实现Servlet接口
public class HelloWorld implements Servlet {
//2.重写里面的方法
@Override
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("<p style='color:red'>Hello World, Servlet!</p>");
}
@Override
.....
}
- 6.配置Servlet项目在
WebContent > WEB-INF > web.xml
添加Servlet的名称以及类.包名称cn.weiyigeek.servlet.HelloWorld
,然后添加注册一个Servlet映射url访问路径,重新发布项目即可;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<?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_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>HelloWorld</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>
<!-- 1.告知Tomcat我们应用中有个Servlet,名字叫做HelloHelloWorld,以及包.类的路径名称; -->
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>cn.weiyigeek.servlet.HelloWorld</servlet-class>
</servlet>
<!-- 2.注册Servlet映射以及URL匹配访问的路径 -->
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<web-app>
响应流程:
(1) 当用户访问http://127.0.0.1:8080/HelloWorld/hello
时候,匹配到了注册的Servlet映射的url路径,反向找到servlet-name应用名称
(2) 再从Servlet应用中查询出该servlet name名称的应用,并反向找到其包名.类
名称;
(3) 编译并且创建cn.weiyigeek.servlet.HelloWorld
该类的实例,然后Tomcat通过Java VM虚拟机运行其所产生的字节码文件;
(4) 继而执行该Servlet中的services方,并且反馈输出到我们的控制台之中;
2.HttpServlet
描述:在Eclipse中选择接口名称按CTRL+T
键,显示其继承层级已经实现了Servlet接口的一些通用写法,来避免重复重写Servlet中的方法;1
Servlet 接口 -> GenericServlet -> HttpServlent (用于处理HTTP的请)
我们参照Tomcat给我们提供的helloworld.html示例文档进行实现,在上面的基础之上添加一个新的class文件,进行继承HttpServlet以及复习doGet和doPost方法;
基础示例: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// cn.weiyigeek.servlet.HttpHelloWorld
package cn.weiyigeek.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Administrator
* 说明:实现 Generial通用httpServet继承的复写
*/
public class HttpHelloWorld extends HttpServlet {
//1.get请求
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应文本内容类型
resp.setContentType("text/html");
//实例化并设置响应文本内容
PrintWriter out = resp.getWriter();
out.print("<!DOCTYPE HTML><html><head><title>HttpServlet Hello</title></head><body><h1>Hello World,HttpServlet!</h1></body></html>");
}
//2.post请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
// Web.xml:添加 servlet 映射
<web-app ...>
<servlet>
<servlet-name>HttpHelloWorld</servlet-name>
<servlet-class>cn.weiyigeek.servlet.HttpHelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HttpHelloWorld</servlet-name>
<url-pattern>/web</url-pattern>
</servlet-mapping>
</web-app>
3.Servlet生命周期
问:什么是生命周期?什么是生命周期方法?
从创建到销毁的一段时间,从创建到销毁的所调用的方法;
Servlet生命周期流程:
- 1.init() 初始化:在创建该Servlet实例时候执行该方法(也可以提前进行初始化后面代码实现),在生命周期内只会在启动后初次访问时候触发一次,后续访问不会再触发;
- 2.service() 服务请求:当客户端每来一个请求就要触发执行该方法;
- 3.destory() 销毁:该项目从tomcat应用中移出的时候以及tomcat服务器正常shutdown的时候会触发执行该方法;
提前Servlet初始化:
描述:在有时候我们可能需要在init初始化这个方法中执行一些初始化工作,甚至做一些比较耗时的操作的逻辑,那么这时我们可以将初始化的时机进行提前到应用启动的时候;
配置:在需要的servlet提前初始化运行的servlet名称下添加load-on-startup元素;
基础示例:
cn.weiyigeek.servlet.Lifecycle1
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
63package cn.weiyigeek.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
*
* @author Administrator
* 说明:Servlet 声明周期的验证
*/
public class Lifecycle implements Servlet {
static int num = 0;
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
System.out.println("1.Lifecycle 初始化操作 ...");
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
// TODO Auto-generated method stub
num++;
System.out.println("2.Lifecycle 服务提供操作,您访问了 "+num+" 次!");
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("3.Lifecycle 销毁操作...");
}
}
//web.xml
<web-app ...>
<!-- 声明周期验证并提前初始化 -->
<servlet>
<servlet-name>Lifecycle</servlet-name>
<servlet-class>cn.weiyigeek.servlet.Lifecycle</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Lifecycle</servlet-name>
<url-pattern>/lifecycletest</url-pattern>
</servlet-mapping>
</web-app>
执行结果: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信息: Starting Servlet Engine: Apache Tomcat/7.0.100
二月 17, 2020 12:21:37 上午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
警告: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [293] milliseconds.
1.Lifecycle 初始化操作 ...
二月 17, 2020 12:21:37 上午 org.apache.catalina.startup.HostConfig deployDescriptor
信息: 部署描述符[D:\apache-tomcat-7.0.100\conf\Catalina\localhost\Demo3.xml]的部署已在[69]ms内完成
二月 17, 2020 12:21:37 上午 org.apache.catalina.core.ApplicationContext log
信息: SessionListener: contextInitialized()
信息: 开始协议处理句柄["http-bio-8080"]
二月 17, 2020 12:21:38 上午 org.apache.catalina.startup.Catalina start
信息: Server startup in 1887 ms
2.Lifecycle 服务提供操作,您访问了 1 次!
2.Lifecycle 服务提供操作,您访问了 2 次!
2.Lifecycle 服务提供操作,您访问了 3 次!
信息: Pausing ProtocolHandler ["http-bio-8080"]
二月 17, 2020 12:32:36 上午 org.apache.catalina.core.StandardService stopInternal
信息: 正在停止服务[Catalina]
3.Lifecycle 销毁操作...
二月 17, 2020 12:32:36 上午 org.apache.catalina.core.ApplicationContext log
信息: SessionListener: contextDestroyed()
二月 17, 2020 12:32:36 上午 org.apache.coyote.AbstractProtocol stop
信息: 正在停止ProtocolHandler ["http-bio-8080"]
二月 17, 2020 12:32:36 上午 org.apache.coyote.AbstractProtocol destroy
信息: 正在摧毁协议处理器 ["http-bio-8080"]
注意事项:
- 1.生命周期方法是指,从对象创建到销毁一定会执行的方法,而doGet和doPost不算生命周期方法因为他们可能会执行或者不会执行;
- 2.Servlet初始化提前load-on-startup值越小优先级越高且是一个正值;
4.Servlet配置对象
描述:我们可以利用Servlet配置对象进行获取或检测web.xml中的servlet配置信息;
在未来我们进行实际开发时候,采用其他人开发出来的servlet类,我们使用它的jar进行导入到我们的工程之中,然后它设置的servlet必须注册某一个参数才可以使用,否则爆出异常;
如何声明init-params和init-values?
在Web.xml中的servlet元素中加入
<init-param><param-name>name</param-name><param-value>WeiyiGeek</param-value></init-param>
等子元素和孙子元素;
基础示例: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///HelloWorld/src/cn/weiyigeek/servlet/SevletConfig.java
package cn.weiyigeek.servlet;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author Administrator
* Descript: 验证ServletConfig的使用获取web.xml配置的信息
*/
public class SevletConfig extends HttpServlet{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获得Servlet配置对象专门用于配置servlet的信息
ServletConfig config = getServletConfig();
//2.可以获取具体servlet配置中的名称;
String servletName = config.getServletName();
System.out.println("Servlet-Name = " + servletName);
//3.检测参数是否存在被设置进行非法参数异常抛出(值得学习 illeal 英 /ɪˈliːɡl/ )
String myself = config.getInitParameter("WeiyiGeek");
if(myself == null) {
throw new IllegalArgumentException("在Servlet配置中未找到WeiyiGeek参数,请核验Web.xml文件!");
} else {
System.out.println("WeiyiGeek load ....");
}
//4.获取单个具体参数
String name = config.getInitParameter("name");
System.out.println("配置文件中 name 值为" + name);
//5.遍历配置中设置的多个参数
Enumeration<String> para = config.getInitParameterNames();
while(para.hasMoreElements()) {
String key = para.nextElement();
String value = config.getInitParameter(key);
System.out.println("参数"+key+",值="+value);
}
}
}
web.xml:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<web-app>
<!-- 4.验证ServletConfig配置 -->
<servlet>
<servlet-name>ServletConfig</servlet-name>
<servlet-class>cn.weiyigeek.servlet.SevletConfig</servlet-class>
<init-param>
<param-name>WeiyiGeek</param-name>
<param-value>ServletConfig</param-value>
</init-param>
<init-param>
<param-name>name</param-name>
<param-value>WeiyiGeek</param-value>
</init-param>
<init-param>
<param-name>age</param-name>
<param-value>88</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletConfig</servlet-name>
<url-pattern>/config</url-pattern>
</servlet-mapping>
</web-app>
执行结果:
5.Servlet配置方式
描述:Servlet 配置方式常用的有三种:
1) 全路径匹配
web.xml 中的
<servlet> </servlet>
标签中以 / 开始 /a 或者 /aa/bb
访问: 127.0.0.1:8080/项目名称/aa//bb 访问即可
2)路径匹配,前版本匹配
以 / 开始,但是以 结束 /a/ 或者 /*;
访问: localhost:8080/项目名称/aa/bb
3) 以扩展名开始
没有 / 而是以 开始 .扩展名称,比如 *.aa 或者 .bb
访问:localhost:8080/项目名称/weiyigeek.aa
在下面我演示Servlet的第二种配置方式:
- 1.右键新建立一个Servlet文件,需要您提供包package和类名称;
2.删除建立的ServletMethod文件中不需要的方法,并且查看web.xml 默认生成的servlet配置;
1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>ServletMethod</display-name>
<servlet-name>ServletMethod</servlet-name>
<servlet-class>cn.weiyigeek.servlet.ServletMethod</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletMethod</servlet-name>
<url-pattern>/ServletMethod</url-pattern>
</servlet-mapping>3.验证上面的配置方式的一种将
url-pattern
进行更改1
2
3-- 1. <url-pattern>/aa/bb</url-pattern>
-- 2. <url-pattern>/aa/*</url-pattern>
-- 3. <url-pattern>*.weiyigeek</url-pattern>
执行结果: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
31package cn.weiyigeek.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation(实现) class ServletMethod
*/
public class ServletMethod extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
System.out.println("有人访问了一个请求...!!");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
0x05 Servlet进阶
1.ServletContext对象
描述:每个JAVA虚拟机中的WEB application应用工程只有一个ServletContext对象,简单的说就是不管在哪一个servlet里面获得到的这个类的对象都是同一个;
ServletContext对象的作用
- 1.获取全局配置参数
- 2.获取Web工程中的资源
- 3.存取数据Servlet间共享数据(域对象)
ServletContext 生命周期
问题:ServletContext何时创建,何时销毁?
创建:服务器启动的时候,会为托管的每一个Web应用程序,创建一个ServletContext对象;
销毁:从服务器移除托管或者是关闭服务器;
ServletContext 作用范围:同一个项目之中共享数据,但是如果是不同的项目之间存取值是不一样的(取不到),因为ServletContext的对象不同;
1) 采用ServletContext获取资源文件
在工程中的web.xml中建立的context-param参数是全局的上下文参数或者在WebContext中建立一个文件夹存储Properties文件;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!-- 1.在Servlet中采用getServletContext获取对象-->
ServletContext context = getServletContext();
<!-- 2.全局上下文参数-->
<context-param>
<param-name>name</param-name>
<param-value>WeiyiGeek</param-value>
</context-param>
<context-param>
<param-name>age</param-name>
<param-value>100</param-value>
</context-param>
<!--3.在WebContext目录中建立一个目录和prop文件-->
Config/WeiyiGeek.Properties;
基础示例: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
69package cn.weiyigeek.servlet;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servletcontext1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//方式1:ServletContext获取资源文件
Scmethod1(response);
//方式2:ServletContext + Propersties 获取资源文件
Scmethod2(response);
//方式3:ServletContext资源文件获取
ServletContext sc = getServletContext();
Properties prop = new Properties();
//给相对路径然后直接获取文件绝对地址和读取文件转化成为流对象
InputStream is = sc.getResourceAsStream("Config/WeiyiGeek.Properties");
prop.load(is);
System.out.println("\n方式三:ServletContext资源文件获取\n");
System.out.println("Name = " + prop.getProperty("name") + "\n");
System.out.println("Age = " + prop.getProperty("age"));
}
//方式2
public void Scmethod2(HttpServletResponse response) throws FileNotFoundException, IOException {
//1.获取上下文对象
ServletContext context = getServletContext();
//2.或者Properties中的参数值采用ServletContext进行读取
Properties prop = new Properties();
String proppath = context.getRealPath("Config/WeiyiGeek.Properties"); //获取到了WeiyiGeek.Properties绝对路径
System.out.println("Properties 配置文件路径 = " + proppath);
//Properties 配置文件路径 = D:\apache-tomcat-7.0.100\wtpwebapps\HelloWorld\Config\WeiyiGeek.Properties
//3.指定properties数据源(但是需要注意这里是web应用,如果想获取web工程的下资源需要采用ServletContext获取配置文件路径)
InputStream is = new FileInputStream(proppath);
prop.load(is);
//4.获取属性的值
String name = prop.getProperty("name");
String age = prop.getProperty("age");
response.getWriter().append("\n ------------------ \n");
response.getWriter().append("ServletContext-> Properties Param Name = ").append(name + "\n");
response.getWriter().append("ServletContext-> Properties Param Age = ").append(age);
}
//方式1
public void Scmethod1(HttpServletResponse response) throws IOException {
//1.获取上下文对象
ServletContext context = getServletContext();
//2.获取web.xml中Context-param中设置全局配置参数的key和value;
response.getWriter().append("ServletContext Param Name = ").append(context.getInitParameter("name") + "\n");
response.getWriter().append("ServletContext Param Age = ").append(context.getInitParameter("age"));
}
}
注意事项:
- 1.在Web工程按照我们前面学习的Properites进行读取配置文件是不行,如果您将prop文件建立在src中在web项目部署的时候会保存到WEB-INF/CLASSES/目录中,导致FileInputStream不能够正常读取到该文件则properties方式也不能获取到参数的值,因为此时FIleInputStream流程读取是bin/src/xxx.Properties;
- 2.解决注意1的方式是采用ServletContext中的getRealPath方法获取到webContext的绝对路径,然后在指定dir/xx.Properties之后常规读取即可
- 3.对注意2进行优化可以直接采用ServletContext中的getResoureAsStream方法读取文件流,然后采用prop.load()加载此对象即可;
2) 使用ClassLoader获取资源文件
描述:采用ClassLoader可以直接读取当前工程下的字节码文件和配置文件;
基础案例: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
26package cn.weiyigeek.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servletcontext2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.打印getClassLoader路径
System.out.println(this.getClass().getClassLoader());
//2.实例化Properties和InputStream对象
Properties prop = new Properties();
InputStream is = this.getClass().getClassLoader().getResourceAsStream("../../Config/WeiyiGeek.Properties");
prop.load(is);
System.out.println("姓名:" + prop.getProperty("name") + ",年龄 : " + prop.getProperty("age") );
is.close();
}
}
访问:1
2
3
4
5
6
7
8
9
10#运行结果:
WebappClassLoader
context: /HelloWorld
delegate: false
repositories:
/WEB-INF/classes/ #因为默认是在这个目录之中,而我们建立的是在WebContext中则需要两次回到上级目录之中
----------> Parent Classloader:
java.net.URLClassLoader@7440e464
姓名:WeiyiGeek,年龄 : 2020
3) ServletContext存取数据
描述:此处采用ServletContext进行获取登录成功的总数,具体流程如下:
- 获取提交过来的数据
- 判断账号密码数据是否有误
- 如果正确进行页面的跳转并且输出”该用户是网站成功登陆的第几人”,采用Servlet记录其值;
- 如果错误输出”登录失败”;
补充说明:一个请求URL对应一个Servlet文件进行处理;
基础语法说明:1
2
3
4
5//获取设置的属性值
getServletContext().getAttribute("key")
//设置属性值
getServletContext().setAttribute("key",value);
实例演示:1
2
3
4
5
6
7//Servlet Class 类
Login
CountTotal
//HTML页面
Login.html
Success.html
基础代码:1
2
3
4
5
6
7
8
9
10
11
12<!-- Login.html -->
<!-- 注意 action 这里由于login.html 与 Login 是处于同一级目录的,您也可以写 /项目名称/Login -->
<form action="Login" method="get">
用户名:<input type="text" name="username"/>
密 码:<input type="password" name="password"/>
<input type="submit" value="登录"/>
</form>
<!-- Success.html -->
<h1> 尊敬的用户您已成功登陆! </h1>
<hr/>
<a href="CountTotal">获取成功登陆的次数</a>
java代码: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//Servlet -> Login
public class Login extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取登录页面传递的参数
String user = request.getParameter("username");
String pass = request.getParameter("password");
System.out.println("Get 请求获取的参数 :user = " + user + "?pass = " + pass );
//2.判断用户输入账号密码是否正确
if("admin".equals(user) && "123".equals(pass))
{
//3.登录成功在响应和终端控制台进行打印
response.getWriter().append("登录成功!");
//4.记录和获取在Servlet中存储登录成功的值
int count = 0;
Object ob = getServletContext().getAttribute("total"); //获取ServletContext属性
if(ob != null )
{
count = (int) ob;
}
getServletContext().setAttribute("total", ++count); //设置存储ServletContext属性
System.out.println("登录成功! 您累积成功登陆 " + count +"次");
//5.设置登录成功跳转页面
response.setStatus(302); //设置状态码
response.setHeader("Location", "success.html"); //设置跳转头
}else {
response.getWriter().print("登录失败,账号或者密码错误!");
System.out.println("账号或者密码错误!");
}
}
}
//Servlet -> CountTotal
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.在ServletContext中获取成功登陆的次数
int total = (int) getServletContext().getAttribute("total");
//2.打印输出成功的次数
response.getWriter().append("尊敬的用户您成功登陆 " + total +" 次");
}
2.HttpServletRequest
1) Request获取请求头
基础语法:1
2request.getHeaderNames(); //返回一个枚举合集Enumeration请求头
request.getHeader("请求头部"); //获取该请求的响应头值
2) Request请求信息提取
基础语法:1
2
3
4
5
6System.out.println("当前客户端协议 :" + request.getProtocol());
System.out.println("当前请求编码 :" + request.getCharacterEncoding());
System.out.println("项目名称 :" + request.getContextPath());
System.out.println("项目URL:" + request.getRequestURI());
System.out.println("本机信息 :" + request.getLocalName() + " - " + request.getLocalAddr() + " - " + request.getLocalPort());
System.out.println("客户端信息 : " + request.getRemoteUser() + " - " + request.getRemoteAddr() + " - " + request.getRemoteHost() + " - " + request.getRemotePort());
3) Request请求数据拿取
基础语法:1
2
3
4
5
6
7//请求参数值获取单个
request.getParameter("key")
//方式1.获取多个请求参数为集合
request.getParameterMap(); // Map Set Iterator 等
//方式2:获取多个请求参数为集合
request.getParameterNames(); // 获得参数名称
request.getParameterValues("key") //利用参数名称查询其值
4) Request请求中文乱码解决
描述:在客户端进行Get/POST请求的时候在URL地址已经经过了url编码,而Tomcat获取到的这批数据getParameter默认使用ISO-8859-1去解码,所以会导致答应中文乱码;
解决办法:1
2
3
4
5
6
7
8
9//1.终端/网页显示不乱码(推荐形式-成功)
String val = new String(value[i].getBytes("ISO-8859-1"),"utf-8");
//2.网页回显不乱码(POST 请求 - 未验证成功)
request.setCharacterEncoding("UTF-8"); //输入的格式不乱码 (需要写在获取参数之前 - POST 请求使用)
//3.直接在Tomcat中进行配置以后GET请求的数据永远都是UTF-8编码
//conf/server.xml
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URLEncoding="UTF-8" />
基础示例(1):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
71package cn.weiyigeek.httpServletRequest;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HttpHeader extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//0.采用网页进行回显
request.setCharacterEncoding("utf-8"); //输入的格式不乱码
response.setContentType("text/html"); //输出格式
//1.枚举集合
response.getWriter().append("------- 请求头获取 ------- <br/>");
Enumeration<String> headers = request.getHeaderNames();
//2.循环迭代请求头
while(headers.hasMoreElements())
{
String reqname = headers.nextElement();
String reqvalue = request.getHeader(reqname);
//3.向网页中进行输出
response.getWriter().append(reqname + ":" + reqvalue + "<br/>");
}
response.getWriter().append("<br/> ------- 获取多个参数 ------- <br/>");
//4.方式1:获取多个请求参数(值得学习)
Map<String, String[]> map= request.getParameterMap(); //map 集合
Set<String> keySet = map.keySet(); //Set 集合
Iterator<String> iterator = keySet.iterator(); //迭代器
while(iterator.hasNext()) {
String key = (String) iterator.next();
String[] value = map.get(key); //默认以首次出现的参数名称为准
//5.验证存在多个相同的参数
if(value.length > 1){
for (int i = 0; i < value.length; i++) {
String val = new String(value[i].getBytes("ISO-8859-1"),"utf-8"); // 防止输入输出的中文乱码(终端|网页)
response.getWriter().append(key+ ":" + val + "<br/>");
}
}else {
response.getWriter().append(key+ ":" + value[0] + "<br/>");
}
}
//6.方式2:获取请求的参数(中文输出不乱码)
Enumeration<String> para = request.getParameterNames();
while(para.hasMoreElements())
{
String paraname = para.nextElement();
String[] value = request.getParameterValues(paraname);
if(value.length > 1) {
for (int j = 0; j < value.length; j++) {
String val = new String(value[j].getBytes("ISO-8859-1"),"utf-8"); // 防止输入输出的中文乱码(终端|网页)
System.out.println(paraname + " = " + val);
}
}else {
System.out.println(paraname + " = " + value[0] + "\n");
}
}
}
}
基础示例(2):POST请求验证输入输出不乱码和请求信息获取;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
36public class HttpPostInfo extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//2.POST请求输出不乱码
request.setCharacterEncoding("UTF-8");
//3.获取输出POST请求的参数
System.out.println("编码设置后 --- name = " + new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8") + "\n----");
//4.获取客户端的信息
System.out.println("当前客户端协议 :" + request.getProtocol());
System.out.println("当前请求编码 :" + request.getCharacterEncoding());
System.out.println("项目名称 :" + request.getContextPath());
System.out.println("项目URL:" + request.getRequestURI());
System.out.println("本机信息 :" + request.getLocalName() + " - " + request.getLocalAddr() + " - " + request.getLocalPort());
System.out.println("客户端信息 : " + request.getRemoteUser() + " - " + request.getRemoteAddr() + " - " + request.getRemoteHost() + " - " + request.getRemotePort());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.POST 请求入口
System.out.println("POST 请求.....");
System.out.println("编码设置前 --- name = " + request.getParameter("name"));
doGet(request, response);
}
}
//基础信息
POST 请求.....
编码设置前 --- name = ??????
编码设置后 --- name = 张伟
----
当前客户端协议 :HTTP/1.1
当前请求编码 :UTF-8
项目名称 :/HelloWorld
项目URL:/HelloWorld/HttpPostInfo
本机信息 :HackOne - 192.168.1.3 - 8080
3.HttpServletResponse
描述: 服务器端返回给客户端的内容信息;
1) 响应数据
基础语法:1
2response.getWriter().write("<h1>字符集</h1>"); //以字符流的方式写数据
response.getOutputStream().write("Hello World!".getBytes()); //字节流的方式写数据
2) 响应中文乱码
描述:在请求响应中有中文字符乱码的存在,在使用Tomcat的Servlet进行写出去的文字默认是以ISO-8859-1编码写出,所以我们需要采用指定编码进行写出防止乱码;
基础语法:1
2
3
4
5
6
7
8// 以字符流的方式
response.setHeader("Content-type","text/html; charset=UTF-8"); //规定浏览器显示什么编码
response.setCharacterEncoding("UTF-8"); //响应内容编码(根据浏览器有关)
response.getWriter().write("<h1>字符集</h1>"); //以字符流的方式写数据
// 以字节流的方式
response.setContentType("text/html; charset=UTF-8"); //响应内容格式和编码
response.getOutputStream().write("中文字符串".getBytes("UTF-8")); //默认输出是UTF-8
总结:
- 不管是字节流还是字符流直接使用setContentType()方法进行响应格式和编码,之后直接写数据即可;
3) 响应头设置
基础语法:1
2response.setStatus(302) //响应状态码设置
response.setHeader("Location","WeiyiGeek.top") //响应头设置
4) Servlet请求重定向和转发
描述:重定向与转发的区别;
- 1.客户端显示URL不同:前者重定向的地址(
此时request对象存储的数据中原来的参数将不会被带人
),后者用户访问的Servlet地址(会将参数一起待入到转发的页面
); - 2.请求次数的不同:前者由于返回302状态码Clint请求了两次,后者只请求了一次;
- 3.跳转的限制:前者任意工程跳转,后者自己项目工程调整;
- 4.效率对比:前者效率较后者低;
基础语法:1
2
3
4
5
6
7
8
9//重定向早期案例
response.setStatus(302);
response.setHeader("Location","Login_Success.html");
//重定向常用案例(即重新定位方向即Login_Success.html网页地址)
response.sendRedirect("Login_Success.html")
//请求转发案例(但是请求的URL还是原地址不是Login_Success.html,服务器内部进行处理了后续的工作)
//带参数和跳转位置进行拼接到请求的Servlet
response.getRequestDispatcher("Login_Success.html").forward(request,response);
5) 资源下载
- 1.采用超连接的形式下载定位静态资源,但是遇到jpg或者txt类型的数据还是可以下载,只不过要右键另存为,所以当我们没有写Servlet文件进行处理,也能进行解析,原因是由于Tomcat里有个默认的Servlet叫DefaultServlet专门处理放在Tomcat服务器上的静态资源;
- 2.手动编码进行下载,设置响应头
Content-Disposition: attachment; filename="文件名称"
;
基础示例:资源下载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
72public class HttpFileDown extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.返回给客户端的文字内容使用的默认编码
response.setCharacterEncoding("UTF-8");
//2.指定浏览器解析数据的格式和编码
//response.setHeader("Content-Type", "text/html; charset=UTF-8");
//3.采用字符流进行输出中文不乱码
String filename = new String(request.getParameter("filename").getBytes("ISO-8859-1"),"UTF-8"); //下载文件带中文字符
//response.getWriter().write("1.字符流(方式):当前您下载的文件是 " + filename + "<br/>");
//String csn = Charset.defaultCharset().name(); //getBytes()默认码表
//response.getWriter().append("2.getBytes()默认码表:" + csn);
//4.采用字节流进行指定编码输出中文不乱码(其实getBytes()方法的默认码表就是UTF-8与Tomcat默认码表无关系)
//response.setContentType("text/html; charset=UTF-8"); //响应内容格式和编码
String path = getServletContext().getRealPath("Config/"+filename);
String name = "3.字节流(方式):当前您下载的文件路径是 :" + path;
//response.getOutputStream().write(name.getBytes("UTF-8")); //注意不能和字符流同时存在;
//response.getOutputStream().print(name);
//5.设置下载文件的响应头并且如果存在中文名称需要对其进行编码;
/*
* 如果IE或者Chrome使用的URLEncoding编码
如果是Firefox使用的是base64编码
*/
String clientType = request.getHeader("User-Agent");
//注意大小写,当然为了方便您可以
if(clientType.contains("Firefox"))
{
filename = base64EncodeFileName(filename);
} else {
filename = URLEncoder.encode(filename,"UTF-8");
}
response.setHeader("Content-Disposition", "attachment; filename="+filename); //返回文件中文不乱码
//6.读取文件到字节流然后进行下载
InputStream is = new FileInputStream(path); //采用绝对路径进行读取文件
OutputStream os = response.getOutputStream();
int len = 0;
byte[] buf = new byte[1024];
while((len = is.read(buf)) != -1)
{
//7.写出文件
os.write(buf, 0, len);
}
//8.关闭输入输出流
os.close();
is.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
//进行Base64编码
public static String base64EncodeFileName(String fileName) {
BASE64Encoder base64Encoder = new BASE64Encoder();
try {
return "=?UTF-8?B?" + new String(base64Encoder.encode(fileName.getBytes("UTF-8"))) + "?=";
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
执行结果:1
2
3
4
5
6#使用getWriter()
1.字符流(方式):当前您下载的文件是 WeiyiGeek.Properties
2.getBytes()默认码表:GBK
#使用getOutPutStream() 注意不能和字符流同时存在
3.字节流(方式):当前您下载的文件路径是 :D:\apache-tomcat-7.0.100\wtpwebapps\HelloWorld\Config\WeiyiGeek.Properties
注意事项:
- 针对于浏览器类型对下载的文件名称做编码处理,Fire采用Base64编码而IE和Google采用URLEncoding编码
0x06 本文总结
ServletContext
介绍:什么是ServletContext?
- 答:服务器在启动的时候给每一个应用程序都创建一个ServletContext,并且有且只有一个;
作用:有什么用?
- 答:获取全局参数 / 获取工程下的资源 / 存取数据和共享数据
例子:怎么用?1
2
3
4
5
6
7
8
9
10
11//获取全局参数
getServletContext().getInitParams();
//获取工程下的资源
getServletContext().getRealPath();
getServletContext().getResourceAsStream();
this.getClass().getClassLoader();
//存取的数据(在同一工程下)
getServletContext.setAttribute()
getServletContext.getAttribute()
实际问题:为什么使用它会产生这个样的样子,其中有其他的参数;
ServletConfig
介绍:什么是ServletConfig?
- 答:是在项目启动部署的时候我们在web.xml中进行对Servlet的配置当我们需要获取Servlet配置信息的时候就需要它;
作用:有什么用?
- 答:获取在Servlet配置web.xml文件中参数;
例子:怎么用?1
2//获取Web.xml中的Servlet配置信息
getServletConfig().getInitParams();
HttpServletResquest
介绍:
- 答:一个请求对象用于封装客户端提交过来的信息;
作用:
- 答:获取头 / 获取客户端参数 / 获取提交过来的数据;
例子:1
request.getParameter("key");
存在问题: GET/POST请求乱码(需要设置编码)
HttpServletResquest
介绍:
- 答:这是一个响应对象,是服务器要给客户端返回的数据,都靠这个对象来完成;
作用:
- 答:返回不同格式的内容 / 页面状态设置和跳转
例子:1
2
3
4
5
6
7//返回不同格式(两种方式)
response.setHeader("Content-Type", "text/html; charset=UTF-8");
response.setContentType("text/html; charset=UTF-8");
//状态码设置
response.setStatus(302);
response.setHeader("Location","")
你好看友,欢迎关注博主微信公众号哟! ❤
这将是我持续更新文章的动力源泉,谢谢支持!(๑′ᴗ‵๑)
温馨提示: 未解锁的用户不能粘贴复制文章内容哟!
方式1.请访问本博主的B站【WeiyiGeek】首页关注UP主,
将自动随机获取解锁验证码。
Method 2.Please visit 【My Twitter】. There is an article verification code in the homepage.
方式3.扫一扫下方二维码,关注本站官方公众号
回复:验证码
将获取解锁(有效期7天)本站所有技术文章哟!
@WeiyiGeek - 为了能到远方,脚下的每一步都不能少
欢迎各位志同道合的朋友一起学习交流,如文章有误请在下方留下您宝贵的经验知识,个人邮箱地址【master#weiyigeek.top】
或者个人公众号【WeiyiGeek】
联系我。
更多文章来源于【WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少】, 个人首页地址( https://weiyigeek.top )
专栏书写不易,如果您觉得这个专栏还不错的,请给这篇专栏 【点个赞、投个币、收个藏、关个注、转个发、赞个助】,这将对我的肯定,我将持续整理发布更多优质原创文章!。
最后更新时间:
文章原始路径:_posts/编程世界/JavaWeb/1.Servlet/Servlet基础入门学习1.md
转载注明出处,原文地址:https://blog.weiyigeek.top/2020/2-11-301.html
本站文章内容遵循 知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议