在webapps目录下新建一个serfis的web应用,在serfis下新建一个WEB-INF\classes,在classes新建servlet(FirstServlet.java)
package com.shen;
import java.io.*;
import javax.servlet.*;
public class FirstServlet extends GenericServlet{
public void service(ServletRequest req,ServletResponse res)
throws ServletException,java.io.IOException
{
String data = "hello servlet!!";
OutputStream out = res.getOutputStream();
out.write(data.getBytes());
}
}
在cmd中进入classes目录,编译FirstServlet(cd/)
javac -d . FirstServlet.java
set classpath=%classpath%;.............(.......为servlet的jar包存放的路径,因为默认的jar包只包含javaSE)
将jar文件直接拖向cmd窗口
在serfis\web-inf目录,新建一个web.xml文件,对servlet进行配置
FirstServlet
com.shen.FirstServlet
FirstServlet
/xxx <表示将该Servlet(FirstServlet)映射到xxx下(因为浏览器通过url访问),/表示当前web项目根目录>
启动服务器,在ie输入http://localhost:8080/serfis/xxx
1).构造器: 只被调用一次. 只有第一次请求 Servlet 时, 创建 Servlet 的实例. 调用构造器. (这说明 Serlvet 的单实例的!)
2). init 方法: 只被调用一次. 在创建好实例后立即被调用. 用于初始化当前 Servlet.
3). service: 被多次调用. 每次请求都会调用 service 方法. 实际用于响应请求的.
4). destroy: 只被调用一次. 在当前 Servlet 所在的 WEB 应用被卸载前调用. 用于释放当前 Servlet 所占用的资源.
注意:在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。service对象在servlet生命周期中服务器只创建一次,并存在Tomcat服务器中,之后再调用该service取之前创建好的对象。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。
Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
编写一个Java类,实现servlet接口。
把开发好的Java类部署到web服务器中。
public class Servletan implements Servlet {
@Override
public void destroy() {//web应用被卸载时调用
// TODO 自动生成的方法存根
System.out.println("destroy");
}
@Override
public ServletConfig getServletConfig() {封装了Servlet配置,并可以获取相关内容属性:servletcontextservletConfig...
// TODO 自动生成的方法存根
System.out.println("getServletConfig");
return null;
}
@Override
public String getServletInfo() {
// TODO 自动生成的方法存根
System.out.println("getServletInfo");
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {//用于初始化,只调用一次
// TODO 自动生成的方法存根
System.out.println("init");
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1)//实际用于响应请求
throws ServletException, IOException {
// TODO 自动生成的方法存根
System.out.println("service");
}
public void hello()
{
System.out.println("hello");
}
}
HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。
HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。
public class HttpServletan extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("hahhah!!");
}
public void doGet(HttpServletRequest request, HttpServletResponse response)//get请求的响应
throws ServletException, IOException {
response.getOutputStream().write("hahhaha".getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);//post请求交由get的请求响应
}
}
在web.xml文件中配置,现有web程序为javaweb,有FirstServlet.java,
FirstServlet
com.shen.FirstServlet
注意:可以通过load-on-startup参数来设置Serlvet 被创建的时机(即init()方法被调用的时间):若为负数, 则在第一次请求时被创建.若为 0 或正数, 则在当前 WEB 应用被
Serlvet 容器加载时创建实例, 且数组越小越早被创建.
FirstServlet
com.shen.FirstServlet
2
FirstServlet
/a.servlet
注意:
1). 同一个Servlet可以被映射到多个URL上,即多个
如:
FirstServlet
/a.servlet
FirstServlet
/b.servlet
在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。
//格式1
FirstServlet
*.do
//格式2
FirstServlet
/*
注意:
1). 以下的既带 / 又带扩展名的不合法.
secondServlet
/*.action
2). 哪个长得像映射哪个,"/"的优先级高于"*"
如:Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do
问题:
当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet1。
当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet3。
当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet1。
当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet2。
当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应?
Servlet引擎将调用Servlet2。
如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。凡是在web.xml文件中找不到匹配的
FirstServlet
/
注意:在
当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。
helloServlet
com.shen.HelloServlet
user
root
password
1230
-1
从init方法中取出初始化参数
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;
public class ConfigServletDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
@Override
public void init(ServletConfig config) throws ServletException {
//获取指定的初始化参数的值
String value = config.getInitParameter("user");
System.out.printfln(value)//打印出root
//获取所有的初始化参数
Enumeration e = config.getInitParameterNames();//Enumeration是一个迭代器
while(e.hasMoreElements()){
String name = (String) e.nextElement();
value = config.getInitParameter(name);
System.out.printfln((name + "=" + value + "
").getBytes());//打印出user root password 1230 }
}
}
然而事实上大部分都在doXXX方法中取出初始化参数故
public class ConfigServletDemo1 extends HttpServlet {
private ServletConfig config;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取指定的初始化参数
String value = config.getInitParameter("xxx");
response.getOutputStream().write(value.getBytes());
//获取所有的初始化参数
Enumeration e = config.getInitParameterNames();//Enumeration是一个迭代器
while(e.hasMoreElements()){
String name = (String) e.nextElement();
value = config.getInitParameter(name);
response.getOutputStream().write((name + "=" + value + "
").getBytes());
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
}
实际上在HttpServlet中重写了init方法(HttpServler继承于GenericServlet,GenericServlet重写了该方法),即同上,故可以在doXXX方法中直接调用ServletConfig
public class ConfigServletDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletConfig config = this.getServletConfig();
System.out.println(config.getInitParameter("user"));
//获取指定的初始化参数
String value = config.getInitParameter("user");
response.getOutputStream().write(value.getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
案例说明:有ServletDemo1,ServletDemo2,现ServletDemo1有数据data="shsj",将其共享给ServletDemo2。
//多个servlet通过servletContext实现数据共享
public class ServletDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "shsj";
ServletContext context = this.getServletConfig().getServletContext();//一般不用该方法
context.setAttribute("datasss", data); //map,将数据data放到关键字datasss中
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
public class ServletDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
String data = (String) context.getAttribute("datasss");//通过关键字获取数据
System.out.println(data);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
1.全局初始化参数的配置
url
jdbc:mysql://localhost:3306/test
2.全局初始化参数的获取
//获取整个web站点的初始化参数
public class ServletContextDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
System.out.println(url);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
案例说明:有ServletDemo1,ServletDemo2,现ServletDemo1有请求,将其转发给ServletDemo2处理。其中ServletDemo2的URL映射为/demo2
//用servletContext实现请求转发
public class ServletDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
RequestDispatcher rd = context.getRequestDispatcher("/demo2");
rd.forward(request, response); //相当于调用ServletDemo2的doget(),故地址栏不变
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
public class ServletDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getOutputStream().write("servletDemo2来处理".getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
分析:
如果ServletDemo1为:
//用servletContext实现请求转发
public class ServletDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
RequestDispatcher rd = context.getRequestDispatcher("/demo2");
rd.forward(request, response); //相当于调用ServletDemo2的doget(),故地址栏不变
System.out.println("我也执行了");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
"我也执行了"将也会被打出,因为请求转发仅仅相当于调用ServletDemo2的doGet方法,如果ServletDemo1为:
//用servletContext实现请求转发
public class ServletDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
RequestDispatcher rd = context.getRequestDispatcher("/demo2");
rd.forward(request, response); //相当于调用ServletDemo2的doget(),故地址栏不变
response.getOutputStream().write("111".getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
"111"不会被浏览器显示出来,因为response已经被发出一次,不会再发出,如果ServletDemo1为:
//用servletContext实现请求转发
//注意:
//1.转发之前的所有写入都无效
//2.转发之前,response不能提交,否则转发的时候服务器会抛:Cannot forward after response has been committed
public class ServletDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getOutputStream().write("111".getBytes());//转发之前写入,值被覆盖
/*
OutputStream out=getOutputStream();
response.out.write("111".getBytes());
out.close //"111将会被写出但报错"
*/
ServletContext context = this.getServletContext();
RequestDispatcher rd = context.getRequestDispatcher("/demo2");
rd.forward(request, response); //相当于调用ServletDemo2的doget(),故地址栏不变
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
有资源文件db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=root
1.资源文件在src目录下
//使用servletContext读取资源文件
public class ServleDemo extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
test2();
}
//做web工程时,不建议采用传统方式读取文件数据
public void test1() throws FileNotFoundException {
FileInputStream in = new FileInputStream("db.properties");//在tomcat服务器中将db.properties文件拷贝到E:\Tomcat8.5\bin后
System.out.println(in);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
//读取web工程中资源文件的模板代码,一般就是这个
private void test2() throws IOException {
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");//源文件在src目录下
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(driver);
}
//通过ServletContext获取路径后再采用传统方式
private void test3() throws IOException {
//获取web资源的绝对路径
String path = this.getServletContext().getRealPath("/WEB-INF/classes/db.properties");//在src目录下
FileInputStream in = new FileInputStream(path);
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
System.out.println(driver);
}
2.资源文件在src目录下com.shen包下
private void test4() throws IOException {
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/shen/db.properties");//源文件在src目录下
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
System.out.println(driver);
}
3.资源文件在webroot目录下
private void test5() throws IOException {
//读取webroot目录下的资源
InputStream in = this.getServletContext().getResourceAsStream("/db.properties");//在webroot目录下
System.out.println(in);
}
4.用类装载器读取
如果一个资源文件在src下(包括包下),更常用类装载器来读取
//用类装载器读取资源文件
public class ServletContextDemo extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
test1();
}
private void test1() throws IOException {
ClassLoader loader = ServletContextDemo.class.getClassLoader();//获取到装载当前类的类装载器
InputStream in = loader.getResourceAsStream("db.properties");//用类装载器装载db.properties文件
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
System.out.println(driver);
}
//读取类路径下面、包下面的资源文件
public void test2(){
InputStream in = ServletContextDemo7.class.getClassLoader().getResourceAsStream("com/shen/db.properties");
System.out.println(in);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意:
1.通过类装载器读取资源文件的注意事项:不适合装载大文件,否则会导致jvm内存溢出
//通过类装载器读取资源文件的注意事项:不适合装载大文件,否则会导致jvm内存溢出
public void test3(){
InputStream in = ServletContextDemo7.class.getClassLoader().getResourceAsStream("PranavMistry_2009I_480.mp4");//如读取一个电影
System.out.println(in);
}
//文件太大,只能用servletContext
public void test4() throws IOException{
//读取PranavMistry_2009I_480.mp4,并拷贝到e:\根目录下
//path=c:\asdf\adsd\add\PranavMistry_2009I_480.mp4
//path=PranavMistry_2009I_480.mp4
////获取文件名
String path = this.getServletContext().getRealPath("/WEB-INF/classes/PranavMistry_2009I_480.mp4");
String filename = path.substring(path.lastIndexOf("\\")+1);//截取到文件名【lastIndexOf("\\")+1表示截取到字符串中最后一个'\'字符后的部分】
//将该文件输入到内存(之前在web服务器)
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/PranavMistry_2009I_480.mp4");
byte buffer[] = new byte[1024];
int len = 0;
//将该文件写入到硬盘
FileOutputStream out = new FileOutputStream("e:\\" + filename);
while((len=in.read(buffer))>0){
out.write(buffer,0,len);
}
out.close();
in.close();
}
2.如果是一个普通的类,因为没有ServletContext对象故只能通过类的装载方法进行数据的读取,Dao.java,通过ServletDemo调用
public class ServletDemo extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Dao dao = new Dao();
dao.run();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
dao.java
public class Dao {
//读取资源文件,并更新资源文件
public void run() throws IOException{
URL url = this.getClass().getClassLoader().getResource("db.properties");
String path = url.getPath();
FileInputStream in = new FileInputStream(path);//读取数据
FileOutputStream out = new FileOutputStream(path);//写入数据
Properties prop = new Properties();
prop.load(in);
System.out.println(prop.size());
prop.setProperty("name", "flx");
prop.store(out, "");
}
}