Servlet入门和ServletConfig、ServletContext
Servlet是一门用于开发动态web资源的技术。
若想开发一个动态web资源,需要完成以下2个步骤:
1)编写一个Java类,实现servlet接口;
2)把开发好的Java类部署到web服务器中。
Servlet快速入门案例
1.建立一个标准的JavaWeb应用目录
FirstApp
------ WEB-INF
--------------classess
--------------lib
--------------web.xml
2.进入classes目录,建立一个文本文件
package cn.lsl.servlet; import java.io.IOException; import java.io.OutputStream; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class FirstServlet extends GenericServlet { public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { OutputStream out = res.getOutputStream(); out.write("Hello Servlet".getBytes()); out.close(); } }
3.进入classes目录,对FirstServlet进行编译:
前提:把servlet-api.jar加入到你的构建路径中.
set classpath=%classpath%;C:\apache-tomcat-6.0.35\lib\servlet-api.jar
执行:javac -d . FirstServlet.java
4.修改web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>cn.lsl.servlet.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
5.部署应用到Tomcat中
6.访问地址:http://localhost:8080/FirstApp/hello
7.Servlet的执行原理和过程图
Servlet的生命周期
容器最终要调用service方法为客户端进行服务
1.Servlet接口中的常用方法:
public void init(ServletConfig config):初始化。Servlet类被实例化之后就会执行,且执行一次。 由容器进行调用
public void destroy():销毁Servlet对象。由容器进行调用。
2.内存中一个Servlet只有一个实例。针对不同的用户请求,容器采用多线程的机制调用service方法。
3.希望在应用被Tomcat加载完毕后(此时还没有任何人访问),就实例化并完成初始化Servlet的工作?
在<Servlet>中配置上<load-on-startup>2</load-on-startup>
<servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>cn.lsl.servlet.FirstServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet>
Servelt接口实现类
1.Servlet接口定义了两个默认实现类
GenericServlet和HttpServlet
2.HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。应该在编写Servlet时,通过应该去继承这个类。
3.HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此在编写Servlet时,通常只需要覆盖doGet或doPost方法,而不要去覆写service方法。
eg:
package cn.lsl.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; public class ServletDemo extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream().write("hello servlet".getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
Servlet的映射
1.一个Servlet可以被映射到多个URL地址上
2.URL地址映射还支持通配符*
方式一:以*开头,以扩展名结尾<url-pattern>*.do</url-pattern>
方式二:以/前缀开头,以*结尾。比如<url-pattern>/action/*</url-pattern>
2. 多个Servlet使用通配符时,有可能有多种
以"/"开头(方式二)要比"*"开头(方式一)优先级高
都以"/"开头,还是有多个匹配,找最匹配的
3. 如果一个Servlet的映射为一个"/",就称之为默认的Servlet,它负责处理没有映射路径的URL请求的响应。
4.在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet。5.当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。
Servlet线程安全问题
当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
解决办法:
1.在Servlet中定义变量,除非特殊要求,尽量使用局部变量
2.如果有需要实例变量,应做同步处理,且同步代码块尽量包围少的代码。
ServletConfig
作用:代表了Servlet配置中的参数信息。
eg:在web.xml中的参数配置如下信息
<servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>cn.lsl.servlet.ServletDemo1</servlet-class> <init-param> <param-name>username</param-name> <param-value>zhangsan</param-value> </init-param> <init-param> <param-name>age</param-name> <param-value>23</param-value> </init-param> </servlet>
package cn.lsl.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; public class ServletDemo1 extends HttpServlet { private ServletConfig config; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { test3(); } //获取指定参数username的值 private void test1(){ String value = config.getInitParameter("username"); System.out.println(value); } //获取所有的参数和参数的值 private void test2(){ Enumeration e = config.getInitParameterNames(); while(e.hasMoreElements()){ String paramName = (String)e.nextElement(); System.out.println(paramName+"="+config.getInitParameter(paramName)); } } //得到servlet的名字 private void test3(){ String name = config.getServletName(); System.out.println(name); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } @Override public void init(ServletConfig config) throws ServletException { this.config = config; } }
ServletContext
1.在应用被服务器加载时就创建ServletContext对象的实例。每一个JavaWeb应用都有唯一的一个ServletContext对象,它就代表着当前应用。
2.如何得到ServletContext对象:ServletConfig.getServletContext();
3.作用
1)ServletContext对象是一个域对象(域对象就是说其内部维护了一个Map<String,Object>)
Object getAttribute(String name):根据名称获取绑定的对象
Enumeration getAttributeNames():获取ServletContex域中的所有名称
void removeAttribute(String name):根据名称移除对象
void setAttribute(String name, Object value):添加或修改对象
2)实现多个Servlet之间的数据共享
eg:
实现ServletDemo2和ServletDemo3之间的数据共享
package cn.lsl.servlet; import java.io.IOException; 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 ServletDemo2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext(); sc.setAttribute("username", "zhangsan"); response.getOutputStream().write("OK".getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
package cn.lsl.servlet; import java.io.IOException; 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 ServletDemo3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext(); String name = (String)sc.getAttribute("username"); response.getOutputStream().write(name.getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
3)获取WEB应用的初始化参数(应用的全局参数)
eg:
在web.xml中
<context-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </context-param>
package cn.lsl.servlet; import java.io.IOException; 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 ServletDemo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext(); String value = sc.getInitParameter("encoding"); response.getOutputStream().write(value.getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
4.读取资源文件的三种方式
1)利用ServletContext.getRealPath():
特点:读取应用中任何文件。只能在web环境下用
文件下载案例:
package cn.lsl.servlet; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; 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 ServletDemo5 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { test2(response); } //英文名文件下载 private void test1(HttpServletResponse response) throws IOException{ //得到要下载的文件 ServletContext sc = getServletContext(); String path = sc.getRealPath("/f.jpg"); //构建输入流 InputStream in = new FileInputStream(path); //通知客户端以下载的方式打开 response.setHeader("Content-Disposition", "attachment;filename=f.jpg"); response.setHeader("Content-Type", "application/octet-stream"); //二进制流 OutputStream out = response.getOutputStream(); int len = -1; byte b[] = new byte[1024]; while((len=in.read(b))!=-1){ out.write(b, 0, len); } in.close(); out.close(); } //中文名文件下载 private void test2(HttpServletResponse response) throws IOException{ //得到要下载的文件 ServletContext sc = getServletContext(); String path = sc.getRealPath("/美女.jpg"); //截取文件名 String filename = path.substring(path.lastIndexOf("\\")+1); System.out.println(filename); //构建输入流 InputStream in = new FileInputStream(path); //通知客户端以下载的方式打开 //中文文件名此处要进行URL编码 response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(filename, "UTF-8")); response.setHeader("Content-Type", "application/octet-stream"); OutputStream out = response.getOutputStream(); int len = -1; byte b[] = new byte[1024]; while((len = in.read(b))!=-1){ out.write(b, 0, len); } in.close(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
2)利用ResourceBundle读取配置文件
特点:可以在非web环境下。但是只能读取类路径中的properties文件。
3)利用类加载器读取配置文件
特点:可以用在非web环境下。可以读取类路径下的任何文件。
eg:
package cn.lsl.servlet; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.ResourceBundle; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //读取资源文件的三种方式 //a1.properties在WEB-INF下 //a2.properties在src下 //a3.properties在src/cn/lsl/resources下 public class ServletDemo6 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { test7(); } //利用ServletContext读取a1.properties private void test1() throws FileNotFoundException, IOException{ ServletContext sc = getServletContext(); String path = sc.getRealPath("/WEB-INF/a1.properties"); Properties props = new Properties(); props.load(new FileInputStream(path)); String value = props.getProperty("username"); System.out.println(value); } //利用ServletContext读取a2.properties private void test2() throws FileNotFoundException, IOException{ ServletContext sc = getServletContext(); String path = sc.getRealPath("/WEB-INF/classes/a2.properties"); Properties props = new Properties(); props.load(new FileInputStream(path)); String value = props.getProperty("username"); System.out.println(value); } //利用ServletContext读取a3.properties private void test3() throws FileNotFoundException, IOException{ ServletContext sc = getServletContext(); String path = sc.getRealPath("/WEB-INF/classes/cn/lsl/resources/a3.properties"); Properties props = new Properties(); props.load(new FileInputStream(path)); String value = props.getProperty("username"); System.out.println(value); } //-------------------------------------- //利用ResourceBundle读取配置文件a2.properties private void test4(){ ResourceBundle rb = ResourceBundle.getBundle("a2"); //基名 String value = rb.getString("username"); System.out.println(value); } //利用ResourceBundle读取配置文件a3.properties private void test5(){ ResourceBundle rb = ResourceBundle.getBundle("cn.lsl.resources.a3"); String value = rb.getString("username"); System.out.println(value); } //-------------------------- //利用类加载器读取配置文件a2.properties public void test6() throws IOException{ ClassLoader cl = ServletDemo6.class.getClassLoader(); InputStream in = cl.getResourceAsStream("a2.properties"); Properties props = new Properties(); props.load(in); String value = props.getProperty("username"); System.out.println(value); } //利用类加载器读取配置文件a3.properties private void test7() throws IOException{ ClassLoader cl = ServletDemo6.class.getClassLoader(); InputStream in = cl.getResourceAsStream("cn/lsl/resources/a3.properties"); Properties props = new Properties(); props.load(in); String value = props.getProperty("username"); System.out.println(value); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }