servlet编程
1 <!-- 配置一个servlet --> 2 <!-- servlet的配置 --> 3 <servlet> 4 <!-- servlet的内部名称,自定义。尽量有意义 --> 5 <servlet-name>FirstServlet</servlet-name> 6 <!-- servlet的类全名: 包名+简单类名 --> 7 <servlet-class>com.nick.FirstServlet</servlet-class> 8 </servlet> 9 10 11 <!-- servlet的映射配置 --> 12 <servlet-mapping> 13 <!-- servlet的内部名称,一定要和上面的内部名称保持一致!! --> 14 <servlet-name>FirstServlet</servlet-name> 15 <!-- servlet的映射路径(访问servlet的名称) --> 16 <url-pattern>/first</url-pattern> 17 </servlet-mapping>
tomcat启动时,首先加载webapps中的每个web应用的web.xml配置文件,并根据web.xml配置文件中的信息来完成对应servlet类对象的创建。
创建流程如下:
(1)tomcat在web.xml中查找是否存在与请求URL匹配的url-pattern的内容
(2)如果存在,就去servlet标签下查找具有相同servlet-name的servlet-class标签,并通过反射机制来完成servlet类的创建。如果不存在就去加载tomcat中的defaultServlet类,defaultServelt会在应用的根目录下查找是否存在index.html的静态文件,如果存在就读取文件内容返回给浏览器。如果不存在则返回404错误页面。
servlet的映射路径--<url-pattern>映射路径</url-pattern>
映射路径分类两种类型:精确匹配和模糊匹配。
精确匹配:如
/first: http://localhost:8080/FirstServlet/first
/first/demo :http://localhost:8080/FirstServlet/first/demo
模糊匹配:如
/*:http://localhost:8080/FirstServlet/任意路径
/first/*:http://localhost:8080/FirstServlet/first/任意路径
*.后缀名:http://localhost:8080/day10/任意路径.后缀名
注意事项:
1)url-pattern要么以 / 开头,要么以*开头。
2)不能同时使用两种模糊匹配,例如 /first/*.do是非法路径
3)当有输入的URL有多个servlet同时被匹配的情况下:
3.1 精确匹配优先。(长的最像优先被匹配)
3.2 以后缀名结尾的模糊url-pattern优先级最低!!!
servlet的缺省路径:
servlet的缺省路径(<url-pattern>/</url-pattern>)是在tomcat服务器内置的一个路径。该路径对应的是一个DefaultServlet(缺省Servlet)。这个缺省的Servlet的作用是用于解析web应用的静态资源文件。
servlet类的声明周期
(1)四个生命周期函数
构造方法: 创建servlet对象的时候调用。默认情况下,第一次访问servlet的时候创建servlet对象只调用1次。servlet对象在tomcat是单实例的。
init方法: 创建完servlet对象的时候调用。只调用1次。--public void init(ServletConfig config);
service方法: 每次发出请求时调用。调用n次。--public void service(ServletRequest req, ServletResponse res);
destroy方法: 销毁servlet对象的时候调用。停止服务器或者重新部署web应用时销毁servlet对象。只调用1次。--public void destroy();
(2)应用的生命周期时序图
servlet自动加载
默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。通过在servlet的web.xml配置信息中,加上一个<load-on-startup>1</load-on-startup>来改变servlet对象在web应用加载的时候就进行创建。
配置示例如下:
<servlet> <servlet-name>LifeDemo</servlet-name> <servlet-class>com.nick.LifeDemo</servlet-class> <!-- 让servlet对象自动加载 --> <load-on-startup>1</load-on-startup> 注意: 整数值越大,创建优先级越低!! </servlet>
注意:在启动servlet的时候进行的逻辑处理应该重写无参的init方法中写,而不用有参的init方法。
servlet线程安全问题
servlet对象在tomcat服务器是单实例多线程的。当多个线程同时访问共享资源的时候,如成员变量等就汇引发线程安全问题。
解决办法:
1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)。
2)建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。
servlet中的对象
(1)HttpServletRequest
(2)HttpServletResponse
(3)ServletConfig
(4)ServletContext
其中HttpServletRequest和HttpServletResponse对象的使用在上一篇博客有介绍,下面主要来看一下ServletConfig和ServletContext对象。
ServletConfig对象
作用:主要是用于加载servlet的初始化参数。在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)。
web应用servlet初始化参数的配置方式:在web.xml中对应的<servlet></servlet>标签下添加初始化参数,配置示例如下:
1 <servlet> 2 <servlet-name>ConfigDemo</servlet-name> 3 <servlet-class>com.nick.ConfigDemo</servlet-class> 4 <!-- 初始参数: 这些参数会在加载web应用的时候,封装到ServletConfig对象中 --> 5 <init-param> 6 <param-name>path</param-name> 7 <param-value>e:/b.txt</param-value> 8 </init-param> 9 </servlet>
获取servletConfig的API:
ServletConfig getServletConfig()
servletConfig常用API:
java.lang.String getInitParameter(java.lang.String name) 根据参数名获取参数值
java.util.Enumeration getInitParameterNames() 获取所有参数
ServletContext getServletContext() 得到servlet上下文对象
java.lang.String getServletName() 得到servlet的名称
servletContext对象
ServletContext对象 ,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一个ServletContext对象。
servletContext对象的核心API:
java.lang.String getContextPath() --得到当前web应用的路径
java.lang.String getInitParameter(java.lang.String name) --得到web应用的初始化参数java.util.Enumeration getInitParameterNames()
void setAttribute(java.lang.String name, java.lang.Object object) --域对象有关的方法java.lang.Object getAttribute(java.lang.String name)
void removeAttribute(java.lang.String name)
RequestDispatcher getRequestDispatcher(java.lang.String path) --转发(类似于重定向)
java.lang.String getRealPath(java.lang.String path) --得到web应用的资源文件java.io.InputStream getResourceAsStream(java.lang.String path)
(1) 获取web应用路径(其实就是项目的名称)--常用于重定位时,代码如下:
1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 //1.得到ServletContext对象 4 ServletContext context = this.getServletContext(); //(推荐使用) 5 6 7 //2.得到web应用路径 /day10 8 /** 9 * web应用路径:部署到tomcat服务器上运行的web应用名称 10 */ 11 String contextPath = context.getContextPath(); 12 System.out.println(contextPath); 13 14 /** 15 * 案例:应用到请求重定向 16 */ 17 response.sendRedirect(contextPath+"/index.html"); 18 }
(2) 得到web应用的初始化参数
在web.xml中配置web应用参数代码如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 8 <!-- 配置web应用参数 --> 9 <context-param> 10 <param-name>AAA</param-name> 11 <param-value>AAA's value</param-value> 12 </context-param> 13 <context-param> 14 <param-name>BBB</param-name> 15 <param-value>BBB's value</param-value> 16 </context-param> 17 <context-param> 18 <param-name>CCC</param-name> 19 <param-value>CCC's value</param-value> 20 </context-param> 21 22 </web-app>
注意:
(1)web应用参数可以让当前web应用的所有servlet获取。
(2) web应用的参数放在<web-app>标签的第一层,每个<context-param></context-param>就是一个web应用的参数。
获取web应用的代码示例如下:
1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 //得到SErvletContext对象 4 ServletContext context = this.getServletContext(); 5 6 System.out.println("参数"+context.getInitParameter("AAA")); 7 8 Enumeration<String> enums = context.getInitParameterNames(); 9 while(enums.hasMoreElements()){ 10 String paramName = enums.nextElement(); 11 String paramValue =context.getInitParameter(paramName); 12 System.out.println(paramName+"="+paramValue); 13 } 14 }
(3) 域对象
域对象的作用:用于保存数据,获取数据。可以在不同的动态资源之间共享数据。
常见的域对象:
HttpServletRequet 域对象
ServletContext域对象
HttpSession 域对象
PageContext域对象
ServletContext作为域对象的使用代码示例如下:
保存对象的java类:
1 class Student{ 2 private String name; 3 private int age; 4 public String getName() { 5 return name; 6 } 7 public void setName(String name) { 8 this.name = name; 9 } 10 public int getAge() { 11 return age; 12 } 13 public void setAge(int age) { 14 this.age = age; 15 } 16 public Student(String name, int age) { 17 super(); 18 this.name = name; 19 this.age = age; 20 } 21 @Override 22 public String toString() { 23 return "Student [age=" + age + ", name=" + name + "]"; 24 } 25 26 }
ServletContext作为域对象保存数据
1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 //1.得到域对象 4 ServletContext context = this.getServletContext(); 5 6 //2.把数据保存到域对象中 7 //context.setAttribute("name", "eric");--普通字符串保存 8 context.setAttribute("student", new Student("jacky",20)); 9 System.out.println("保存成功"); 10 }
ServletContext作为域对象获取数据
1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 //1.得到域对象 4 ServletContext context = this.getServletContext(); 5 6 //2.从域对象中取出数据 7 Student student = (Student)context.getAttribute("student"); 8 System.out.println(student); 9 }
注意:ServletContext域对象的作用于为整个web工程。
(4) 转发
一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为请求转发。
一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源,称之为请求重定向。
转发的代码示例如下:
1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 this.getServletContext().getRequestDispatcher("/GetDateServlet").forward(request, response); 4 }
转发和重定向的区别:
1)转发
a)地址栏不会改变。
b)转发只能转发到当前web应用内的资源。
c)可以在转发过程中,可以把数据保存到request域对象中。
2)重定向
a)地址栏会改变,变成重定向到地址。
b)重定向可以跳转到当前web应用,或其他web应用,甚至是外部域名网站。
c)不能在重定向的过程,把数据保存到request中。
(5) 得到web应用中的资源文件
web应用中用到路径先写上/。
1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 response.setContentType("text/html;charset=utf-8"); 4 //目标资源: target.html 5 /** 6 * 1.转发 7 */ 8 //request.getRequestDispatcher("/target.html").forward(request, response); 9 10 11 /** 12 * 2.请求重定向 13 */ 14 //response.sendRedirect("/day11/target.html"); 15 16 /** 17 * 3.html页面的超连接href 18 */ 19 response.getWriter().write("<html><body><a href='/day11/target.html'>超链接</a></body></html>"); 20 21 /** 22 * 4.html页面中的form提交地址 23 */ 24 response.getWriter().write("<html><body><form action='/day11/target.html'><input type='submit'/></form></body></html>"); 25 }
.:代表java命令行目录,即tomcat/bin目录。
使用ServletContext加载资源文件的方法示例如下:
1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 4 //读取文件。在web项目下不要这样读取。因为.表示在tomcat/bin目录下 5 /*File file = new File("./src/db.properties"); 6 FileInputStream in = new FileInputStream(file);*/ 7 8 /** 9 * 使用web应用下加载资源文件的方法 10 */ 11 /** 12 * 1. getRealPath读取,返回资源文件的绝对路径 13 */ 14 /*String path = this.getServletContext().getRealPath("/WEB-INF/classes/db.properties"); 15 System.out.println(path); 16 File file = new File(path); 17 FileInputStream in = new FileInputStream(file);*/ 18 19 /** 20 * 2. getResourceAsStream() 得到资源文件,返回的是输入流 21 */ 22 InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); 23 24 25 Properties prop = new Properties(); 26 //读取资源文件 27 prop.load(in); 28 29 String user = prop.getProperty("user"); 30 String password = prop.getProperty("password"); 31 System.out.println("user="+user); 32 System.out.println("password="+password); 33 34 }