特此说明:本文参考传智播客、黑马程序员视频讲座 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
servlet简介
servlet(Server Applet)是运行在服务端的java小程序,是sun公司提供的一套规范(接口),用来处理客户端请求、响应给浏览器的动态资源。servlet实质就是java代码,通过java的API动态的向客户端输出内容。
servlet规范:包含三个技术点
- 1)servlet技术
- 2)filter技术(过滤器)
- 3)listener技术(监听器)
servlet快速入门
通过在浏览器中输入访问地址,实现在控制台打印启动情况。操作步骤如下:
- 新建一个Dynamic Web Project
- 书写Servlet接口的实现类及service方法(默认会执行这个方法)
- 书写web.xml配置文件
FirstServlet.java
package com.ccnuacmhdu.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;
public class FirstServlet implements Servlet{
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
System.out.println("FirstServlet starting...");
}
public void destroy() {
// TODO Auto-generated method stub
}
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
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_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>WEB13</display-name>
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>com.ccnuacmhdu.servlet.FirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/FirstServlet</url-pattern>
</servlet-mapping>
<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>
</web-app>
【实验结果】
【遇到的问题及解决方案】
书写Servlet接口实现类时,报红错,没有导入Servlet相关包的提示?
答:不要导入包,Tomcat自身就有相关的包,应该配置一个Tomcat服务器,选中工程—右键–Build Path–Configure Build Path–Libraries–Add Library–Server Runtime–Tomcat
Tomcat服务器启动老是失败?
答:换一个Tomcat服务器试试即可
Servlet的API(生命周期)
servlet接口包含的方法
书写一个Servlet接口的实现类,既可引入其方法,可以看到这些
public void destroy() {
// TODO Auto-generated method stub
}
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
// TODO Auto-generated method stub
}
测试每个方法何时执行的时候,要从服务器开始启动开始来测!可以在每个方法中在控制台打印一些信息,来进行测试
- 1)init(ServletConfig config)
servlet对象创建的时候执行
ServletConfig :该servlet对象的配置信息,可以通过调用这个对象的方法拿到Servlet的一些配置信息 - 2)service(ServletRequest request,ServletResponse response)
每次请求都会执行 - 3)destroy()
servlet销毁的时候执行
Servlet的生命周期
- 1)Servlet何时创建 :默认(注意这里说的是默认,另外可以通过一些配置,让服务器在启动的同时就创建)第一次访问servlet时创建该对象
- 2)Servlet何时销毁 :服务器关闭servlet就销毁了
- 3)每次访问必然执行的方法: service(ServletRequest req, ServletResponse res)方法
由上面可知,默认情况下,第一次通过浏览器访问的时候服务器创建Servlet对象,通过对象来调用init方法(仅执行一次),service方法(每次访问都会执行)。注意init方法、service方法等都不是静态方法,必须通过对象来调用,Servlet对象是Tomcat服务器创建的。
Servlet访问的大致过程
Servlet配置
- 书写配置文件时候,各个配置信息的先后顺序也要注意,顺序变动,可能会报错
- 注意全局web.xml,Tomcat服务器下的conf文件夹下的web.xml是一个全局配置文件,对Tomcat下的所有工程都适用,如果自己写的工程里面的配置信息和这个全局的web.xml配置信息有重合部分,则自己的会覆盖掉全局的。
基本配置
<!-- Servlet类的配置 -->
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>com.ccnuacmhdu.servlet.FirstServlet</servlet-class>
</servlet>
<!-- Servlet虚拟路径配置 -->
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/FirstServlet</url-pattern>
</servlet-mapping>
url-pattern的三种配置方式:
- 1)完全匹配,访问资源地址与配置资源地址必须完全一致
<url-pattern>/FirstServlet</url-pattern> - 2)目录匹配。下面的例子是目录/abc/def/下面的所有资源都可以访问到 “`
/abc/def/*
- 3)扩展名匹配。下面的例子是只要是以扩展名.abc结束的资源都可以访问到 ```
<url-pattern>*.abc</url-pattern> ```
服务器启动实例化Servlet配置
Servlet**默认**情况下是第一次访问时创建对象的。现在要通过配置,使得在启动服务器的时候就创建Servlet对象:<load-on-startup>3</load-on-startup>
这个数越小,优先级越高。
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>com.ccnuacmhdu.servlet.FirstServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
缺省Servlet
将url-pattern配置一个/,代表该servlet是缺省的servlet。当访问资源地址所有的servlet都不匹配时 , 缺省的servlet负责处理。
其实,web应用中所有的资源的响应都是servlet负责,包括静态资源
注意在Tomcat的全局配置文件web.xml中也配置了缺省servlet:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
欢迎页面
<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>
当请求资源地址是上面是http://localhost:8080/WEB13/
默认打开的页面是index.html如果工程WebContent下没有index.html,默认打开index.htm,以此类推。
如果工程里面写了index.html,把上面的配置信息删除,发现再次访问,也会默认打开index.html,这是为什么呢?因为在Tomcat的全局配置文件web.xml里面已经配置了:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
HttpServlet类
为什么可以只写doGet方法和doPost方法?(查看源码说明这个问题)
- 实际开发中使用的是HttpServlet类,而不是上面介绍的Servlet接口。而HttpServlet类本身继承了GenericServlet类,GenericServlet类实现了Servlet接口。可以导入Tomcat源码,在类名上Ctrl点击依次查看源码。
- 可以直接新建一个Servlet,建好后,相应的配置信息也会在配置文件中配置好。当访问时,寻找service方法,但是HttpServlet本身没有这个方法,于是就从HttpServlet的父类以及所实现的接口不断寻找上一级,查看源代码发现在HttpServlet中可以找到service方法,再看源码,发现这个方法会调用另一个已经写好的service方法,而这个service方法里面就有doGet方法和doPost方法的调用选择。我们会重写doGet方法和doPost方法,所以在通过service调用doGet方法或doPost方法时就是在调用我们自己写的方法。
package com.ccnuacmhdu.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 SecondServlet
*/
public class SecondServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public SecondServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @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());
}
/**
* @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);
}
}
怎么自定义模板?
- 上面有很多无用的注释,为了想直接去除所有注释,我们引入了自定义模板,可以通过自己定义模板。Windows—Preferences—Java—Editor—Templates。定义完模板之后,再输入模板名字,就能联想出来这个模板的代码啦!
实例:用户登录
使用原生JDBC
数据库:
login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/WEB13/login" method="post">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登录"><br/>
</form>
</body>
</html>
LoginServlet.java
package com.ccnuacmhdu.login;
import java.io.IOException;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import org.apache.catalina.User;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import com.ccnuacmhdu.utils.DataSourceUtils;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、获得用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
//1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2.获得链接
Connection connection=(Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/web13","root","123");
//3.创建执行sql语句的对象
Statement statement=(Statement) connection.createStatement();
//4.书写SQL语句
String sql="select * from user where "+"username='"+username+"' and password='"+password+"'";
//5.执行SQL语句
ResultSet resultSet=statement.executeQuery(sql);
//6.处理结果集
if(resultSet.next()) {
System.out.println("恭喜您,"+username+"登录成功!");
response.getWriter().write("success");
}
else {
System.out.println("账号或密码错误!");
response.getWriter().write("fail");
}
if(resultSet!=null){
resultSet.close();
}
if(statement!=null) {
statement.close();
}
if(connection!=null) {
connection.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
User.java
package com.ccnuacmhdu.domain;
public class User {
private int id;
private String username;
private String password;
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", email=" + email + "]";
}
}
web.xml主要配置
<servlet>
<description></description>
<display-name>LoginServlet</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.ccnuacmhdu.login.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
ServletContext对象
什么是ServletContext?
ServletContext代表一个web应用的环境(上下文)对象,内部封装该web应用的信息,每个web应用只有一个。
ServletContext对象的生命周期?
创建:该WEB应用被加载(应用发布)
销毁:该WEB应用被卸载(从服务器中移除web应用或关闭服务器)
怎么获得ServletContext对象?
方法一:ServletContext servletContext = config.getServletContext();
方法二:ServletContext servletContext = this.getServletContext();
ServletContext对象的作用
(1)获取web应用全局初始化参数
在web应用中配置如下:
获取配置参数如下,发布应用到Tomcat,访问http://localhost:8080/WEB13/ContextServlet控制台打印value
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获得ServletContext对象
ServletContext servletContext = this.getServletContext();
//获得全局初始化参数
String ininParameter = servletContext.getInitParameter("key");
System.out.println(ininParameter);
}
(2)获得web应用中任何资源的绝对路径(重要*重要重要!!!)*
package com.ccnuacmhdu.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 ContextServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获得ServletContext对象
ServletContext servletContext = this.getServletContext();
//获得全局初始化参数
String ininParameter = servletContext.getInitParameter("key");
System.out.println(ininParameter);
//获得绝对路径(相对于web应用,即WEB13,指的是发布到Tomcat之后的
//a.txt不在WebContent下,不会发布到Tomcat,不能找到a.txt的路径
String realPath_b = servletContext.getRealPath("/WEB-INF/b.txt");
System.out.println(realPath_b);
String realPath_c = servletContext.getRealPath("/WEB-INF/classes/c.txt");//src会发布到classes
System.out.println(realPath_c);
String realPath_d = servletContext.getRealPath("d.txt");
System.out.println(realPath_d);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
控制台打印如下:
value
D:\apache-tomcat-7.0.52\webapps\WEB13\WEB-INF\b.txt
D:\apache-tomcat-7.0.52\webapps\WEB13\WEB-INF\classes\c.txt
D:\apache-tomcat-7.0.52\webapps\WEB13\d.txt
注意:上述获取的路径就是发布到Tomcat中的应用的路径
还可以使用类加载器进行获得绝对路径,这是传入的参数不是相对于应用的路径,而是相对于classes的路径,具体代码及结果如下:
//用类加载器获取路径,是相对于classes的路径
String path_b = ContextServlet.class.getClassLoader().getResource("../b.txt").getPath();
System.out.println(path_b);
String path_c = ContextServlet.class.getClassLoader().getResource("c.txt").getPath();
System.out.println(path_c);
String path_d = ContextServlet.class.getClassLoader().getResource("../../d.txt").getPath();
System.out.println(path_d);
打印结果
/D:/apache-tomcat-7.0.52/webapps/WEB13/WEB-INF/b.txt
/D:/apache-tomcat-7.0.52/webapps/WEB13/WEB-INF/classes/c.txt
/D:/apache-tomcat-7.0.52/webapps/WEB13/d.txt
(3)ServletContext是一个域对象(重要!!!)
一个应用中有一个ServletContext对象,有多个Servlet对象。把ServletContext类比成一个箱子,Servlet类比成若干个顾客,所有的Servlet都可以把东西(键值对)存到ServletContext,其他的Servlet都可以根据ServletContext里面的键拿到值。
ServletContext域对象作用范围:整个web应用(所有web资源都可以随意向ServletContext域中存取数据,数据可以共享)
域对象通用的方法:
setAttribute(String name,Object obj);
getAttribute(String name);
removeAttribute(String name);
实例:显示第几个用户登录的
在上一个用户登录实例的基础上,改进!
在LoginServlet类里增加:
@Override
public void init() throws ServletException {
Integer count = 0;
this.getServletContext().setAttribute("count", count);
}
改进:
if(resultSet.next()) {
ServletContext servletContext = this.getServletContext();
Integer count = (Integer) servletContext.getAttribute("count");
count++;
System.out.println("恭喜您,"+username+"登录成功!,您是第"+count+"个登录的");
response.getWriter().write("成功登录,您是第"+count+"个登录的");
servletContext.setAttribute("count", count);
}
重新发布工程,即可!