Servlet基础
一 Servlet及web服务器相关概念(了解)
tomcat配置(能熟练操作)
二 Servlet基础(重点,必须熟记于心)
a.Servlet的调用过程
b.Servlet接口
c.servlet的生命周期
d.MVC框架
e.Servlet的控制流转
f.Servlet的url-pattern
三 Session(会话)和Cookie(熟记于心)
四 Servlet过滤器和监听器(熟练使用)
五数据库连接池(了解)
一、Servlet及web服务器相关概念
Servlet,服务器端的小程序,它是相对于Applet而言的,Applet是客户端小程序。
Servlet,能接受来自网络的请求(form表单,以及其他的请求),并对不同请求作出不同的响应
servlet是运行在web容器中, web容器可以控制Servlet对象的生命周期,控制请求由Servlet对象处理。
web服务器,这里的服务器不是硬件概念,而是软件,常用的web服务器有 Tomcat,Jboss等,我们所用到的Tomcat是一个开源的服务器,Tomcat是一个用java语言编写的web服务器,所以需要有相应的java运行环境,也就是JVM,还要配置tomcat的具体路径。
Tomcat的配置
JAVA_HOME=/XXX/XXX/(JDK路径,bin的上一层目录)
CATALINA_HOME=/XXXX/XXX
(tomcat的绝对路径 windows中 X:\xxx\xxx linux /home/tarena/tomcat5)
Tomcat启动:$ CATALINA_HOME/bin/startup.sh 或 startup.bat
Tomcat关闭:$ CATALINA_HOME/bin/shutdown.sh 或 shutdown.bat
Tomcat测试启动是否成功:http://localhost:8080/或http://127.0.0.1:8080/可以访问到tomcat的主页就是启动成功了。(这里建议使用127.0.0.1)
tomcat可以识别的资源只有在webapps文件夹下,webapps也就是web应用文件夹,webapps下的文件夹这些文件夹中存放的就是web应用,web应用是有格式规范的:
XXX应用
|- *.jsp *.html *.js *.css *.jpg
|- WEB-INF (受保护资源)
|- classes *.class
|- lib *.jar
|- web.xml
在tomcat服务器中,访问应用下的资源可以在端口号后加上web应用文件夹的名字就可以看到资源
http://localhost:8080/xxx应用/xxxx.html,静态页面只能放在web应用的文件夹下,不能够放在WEB-INF文件夹下,WEB-INF文件夹中的资源是受保护的,不能够通过网络访问到。
Servlet基础
Servlet,可以实现动态的输出页面,可以针对不同的请求作出不同的响应,可以实现页面的跳转,Servlet可以充当MVC模式中的控制层,而且servlet的优点也在于此。
web服务器会在web应用/WEB-INF/classes文件夹搜索要加载的class文件,所以我们写的class文件要放在web应用/WEB-IN/classes文件夹下。
设置servlet的类和访问的方式
web.xml文件的配置,一个web.xml中可以配置多个Servlet
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>servlet的名字</servlet-name>
<servlet-class>servlet包名类名</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet的名字(要和servlet标签中的相同)</servlet-name>
<url-pattern>指定servlet相对于应用目录的路径</url-pattern>
</servlet-mapping>
</web-app>
catalina.sh run 带控制台启动tomcat服务器。
a.Servlet的调用过程
1,用户通过浏览器向web服务器发送请求
http://serverip:port/apppath
2,服务器为用户定位资源
静态资源:/a.html /a/b.html (这里的路径是针对web应用文件夹目录)读文件并把内容发送到客户端
动态资源:解析web.xml定位Servlet类的名字
装载类(WEB-INF/classes|WEB-INF/lib/*.jar)
创建该对象的实例
Servlet ser=(Servlet)(Class.forName("servle的类名")).newInstance();
//我们写的Servlet一定要实现Servlet接口或者继承实现了Servlet接口的类
ser.service(request,response);
<servlet-mapping>
<servlet-name>servlet的名字(要和servlet标签中的相同)</servlet-name>
<url-pattern>指定servlet相对于应用目录的路径</url-pattern>
</servlet-mapping>
url-parttern的配置,这个url就是Servlet的虚拟路径,可以使用相对路径或者是绝对路径。
/xxx/xxx(绝对路径) ,xxx(相对路径),尽量使用绝对路径。
访问servlet的方法
http://serverip:port/应用文件夹名/url-pattern
http的请求
get请求,post请求。
get请求在发出请求时会把参数写在地址栏上,而post请求不会把要发送的参数显示在地址栏上。
<form method="get" action="/应用名/url-pattern">
......
</form>
b.Servlet接口
servlet接口的实现类中的service()方法,在继承HttpServlet类时,如果没有覆盖父类的service()方法,那么父类的service()方法会根据请求类型不同的会分别调用覆盖的doGet(),doPost()方法,如果响应两种请求的动作相同,那么可以直接覆盖service()方法。如果覆盖了
doGet(),doPost()方法之一,那么就会只对一种请求作出响应。在浏览器的地址栏操作按回车键,或者是热连接,都是get请求,form的method属性如果不指定,默认为get请求。
我们可以通过ServletRequest对象或HttpServletRequest对象的方法来获取请求中传送的参数。
getParameter(String name)方法,可以获得form表单中指定名字的参数,多参数同名时,只取一个。
getParameterNames(),可以获得一个迭代器Enumeration,通过这个迭代器,来获得form表单中参数的名字。
getParameterValues(String name)获得指定的所有同名参数的值。
get请求,会将参数显示在浏览器的地址栏上,其显示格式,在地址之后会以问号开始,以'&'分隔参数,可以通过HttpServletRequest对象的getQueryString()方法来获得get请求的参数值。
ServletRequest对象的getInputStream()方法可以获得一个由Socket得来的输入流,可以使用这个流来实现文件的上传。getReader()方法可以直接获取post请求的参数。
ServletContext对象是Servlet的上下文对象,这个对象是在服务器启动时创建的,他可以看作是
一个应用的对象,他可以看作是包含Servlet,管理Servlet的对象。
c.servlet的生命周期
遵守servlet规范的类,就可以通过服务器产生对象(反射机制),并处理请求。
servlet接口中的方法
实现Servlet接口
public class TestServlet implements Servlet {
ServletConfig config;
public void init(ServletConfig config) throws ServletException {
this.config=config;
//这个ServletConfig对象是由服务器生成,也就是由系统提供的,
通过他可以获得启动信息。ServletConfig对象和Servlet是一一对应的。
//这个方法是在Servlet创建后调用的。如果要是用到ServletConfig对象是一 定要为对象赋值。
}
public ServletConfig getServletConfig() {
return this.config;
}
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
...;//这个方法是用来处理请求的核心方法
}
public String getServletInfo() {
return "....";//这个是用来写Servlet信息的,用来写作者,以及版本信息
}
public void destroy() {
...;//这个方法是用来销毁Servlet对象的
}
}
HttpServlet和GenericServlet都实现了Servlet接口。
HttpServlet中的service(HttpServletRequest request,HttpServletResponse response)方法是通过service(ServletRequest request,ServletResponse response)方法的调用来实现对请求的处理。
HttpServletRequest对象中的方法setAttribute(String name,Object o),可以使用HttpServletRequest对象来携带信息,并且可以通过getAttribute(String name)方法来获得携带的信息,这两个方法类似于map中的存取方法,setAttribute方法给数据加上标识,getAttribute方法则是通过这个标识来获取数据,可以使用这一对方法的前提就是要保证是同一个请求对象(HttpServletRequest)
HttpServletResponse类
HttpServletResponse是用来回应用户的操作的,它可以实现页面的重定向。
sendRedirect(String location),是用这个方法指定要访问的servlet,其参数是Servlet的url-pattern
如果使用了重定向,就不会保留原有的request对象。
Servlet的生命周期分为四个阶段
1,创建Servlet对象,通过服务器反射机制创建Servlet对象,第一次请求时才会创建。(默认)
2,调用Servlet对象的init()方法,初始化Servlet的信息,init()方法只会在创建后被调用一次
3,响应请求,调用service()或者是doGet(),doPost()方法来处理请求,这些方法是运行的在多线程状态下的。
4,在长时间没有被调用或者是服务器关闭时,会调用destroy()方法来销毁Servlet对象。
可以通过web.xml文件可以配置Servlet对象的创建时间,
<load-on-startup>数字</load-on-startup>,表示服务器启动时创建,并依照数字大小按顺序创建,只有重要的Servlet才会是用这个设置。
可以通过<init-param>标签来配置初始化参数,可以用ServletConfig对象的
getInitParameter(String name)方法来得到参数。
<init-param>
<param-name>...</param-name>
<param-value>...</param-value>
</init-param>
多线程下所操作的变量,如果操作的是一个变量,且兼有读写操作,就要考虑加上同步,但同步不能乱加,否则会造成死锁问题。
init()和destroy()方法都是运行在单线程下的。
GenericServlet类中的有参和无参的init方法。
public void init(ServletConfig config)throws ServletException
{
this.config = config;
init();
}
public void init()throws ServletException
{
.....;//覆盖了的无参的init()方法,会在Servlet创建时调用有参的init方法时
也会被调用。
}
HttpServlet类中参数不同的service方法的调用关系。
public void service(HttpServletRequest req,HttpServletResponse res){
.......;
.......;
}
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
try
{
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
}
catch(ClassCastException e)
{
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
Servlet的资源访问
如果在Servlet中要使用到其他的资源,例如连接数据库的驱动,可以放在tomcat服务器的文件夹下的common/lib下,这个目录中存放的是一些在服务器启动时就会加载的公共资源,一般在需要在应用中使用特定的资源,也就是jar文件,那么不要放在common/lib下,如果common/lib下的jar文件过多会导致服务器启动缓慢,应用中使用到的jar文件要放在WEB-INF/lib下,就可以被服务器找到了。
如果要在Servlet中是用Hibernate的访问数据库的方法,那么就需要把hibernate需要的jar文件,放到WEB-INF/lib下就可以了,Xxxxxx.hbm.xml还是和实体类放在一起。hibernate.cgf.xml文件,要放在WEB-INF/classes下就可以了。
d.MVC框架
Model,模型层,这一层一般是进行数据库访问,并且封装对象,这一层中也存放对业务处理的代码(业务层)、 与数据库交互的代码(DAO层)和实体类的信息,可以使用JavaBean来完成业务层,使用JDBC、 Hibernate或jpa完成DAO层的功能。
Ctrl,控制层,用来处理请求和调用模型层中相应的方法,这一层是用来控制请求的响应的,现在我们是使用Servlet来实现这一层,不过一般是会用开源的MVC框架来实现这层,例如struts、webwork或者是Spring的MVC框架。
View,表现层,他只用来显示数据和收集必要数据,收集数据的一般是form表单,不过要保证数据的正确性要是用JavaScript做前台验证,而且后台验证也是必不可少的,html、 JSP就是用来表现、显示数据的。
e.Servlet的控制流转
ServletContext,Servlet上下文对象,在每个Servlet中都会有一个ServletContext的引用,这个ServletContext是一个全局的对象,每个应用中只有一个ServletContext对象。
HttpServlet中的getServletContext()方法,获得ServletContext对象。
ServletContext类的getRequestDispatcher(String path)方法获得一个RequestDispatcher对象,并且跳转到指定的Servlet,getRequestDispatcher(String path)方法中的参数就是path,就是指定跳转的Servlet的url-pattern。
RequestDispatcher类的forward(ServletRequest request, ServletResponse response) 方法,可以把请求对象转发给其他的Servlet。
f.Servlet的url-pattern
url-pattern可以使用以下三种方式
1,确切路径匹配,也就是给出确定的路径 xxx/xxxx
2,模糊路径匹配,也就是指给出一部分路径,xxxx/*,他会匹配确定路径,也就是xxxx/a 或者是xxxx/b都是可以匹配的
3,扩展名匹配,也就是会匹配扩展名,只要是扩展名相同就匹配,xxx.xxx *.xx
注意:扩展名匹配和确切路径匹配不能放在一起使用,也就是不能写成 xxxx/xxxx/xxx.xx,但是可以用
*.xxx。
ServletRequest对象的三个返回路径的方法
getContextPath()获得应用的路径,用动态获取应用路径
getServletPath()获得Servlet路径,也就是form中的action,如果使用确切路径那么就会是这个Servlet配置的url-pattern。
getPathInfo()使用模糊路径匹配时会返回匹配模糊部分。
注意:在html的form表单的action中,如果使用了扩展名匹配,一定要写明/xxxxx/xxx.xx,不要写成/xxxx/*.xx,在form的action中要尽量使用绝对路径,也就是要用 应用名/xxx.xx或者应用名/xxx。
三、Session(会话)和Cookie
Session对象用来解决客户端发送多个请求时用户请求信息的存储问题,但是他和ServletRequest对象是不同的,他会在有需要时创建,但是他的生命周期会比请求对象要长。Session对象的生命周期也是有限制的,如果长时间的没有访问,就会销毁掉Session对象,可以通过Session对象的
setAttribute(String name, Object o) 和getAttribute(String name)来存取数据信息。Session是用户级的对象。
public void service(ServletRequest request,ServletResponse response){
String user = request.getParameter("user");
String pass = request.getParameter("pass");
HttpSession session = request.getSession(true);//使用请求对象来创建Session
session.setAttribute("username", user);
session.setAttribute("passwd", pass);
}
getSession(true)就表示如果Session不存在就创建一个新的Session,并把Session的标识SessionID写到Cookie中,如果存在就是用这个Session。getSession(false)就是在Session不存在时不会创建新Session而是返回null。如果使用getSession()方法,就等同于getSession(true)。
注意:ServletRequest对象适用于传输大量的数据,因为其生命周期比较短,可以有效的节省内存资源。
大数据量的传输或保存不适合使用Session空间。
Cookie,是记录用户的Session信息,也可以记录用户的请求信息,也就是SessionID,来分辨哪一个用户是否登陆过。在每次登陆时,还会将Cookie发送回服务器端,Cookie是用来跟踪Session的。
public void service(ServletRequest request,ServletResponse response){
String user = request.getParameter("user");
String pass = request.getParameter("pass");
Cookie userCookie = new Cookie("user", user);
userCookie.setMaxAge(60 * 60 * 24 * 365);//设置Cookie的最大有效期,秒为单位
Cookie passCookie = new Cookie("pass", pass);
passCookie.setMaxAge(60 * 60 * 24 * 365);
response.addCookie(userCookie);
response.addCookie(passCookie);
}
面试题:描述Cookie和Session的作用,区别和各自的应用范围,Session工作原理。
cookie机制采用的是在客户端保持状态的方案
session机制采用的是在服务器端保持状态的方案。
失效不同:
session
A.程序调用HttpSession.invalidate()
B.距离上一次收到客户端发送的sessionid时间间隔超过了session的最大有效时间
C.服务器进程被停止
Cookie 会一直存放在客户端机器上,除非超出Cookie 的生命期限。
Session是由应用服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的SessionID,用该SessionID 为标识符来存取服务器端的Session存储空间。而SessionID这一数据则是保存到客户端,用Cookie保存的,用户提交页面时,会将这一 SessionID提交到服务器端,来存取Session数据。这一过程,是不用开发人员干预的。所以一旦客户端禁用Cookie,那么Session也会失效。
四、Servlet过滤器和监听器
Servlet过滤器(Filter)
过滤器是用于过滤Servlet的请求和响应,过滤器是存在于请求和被请求资源之间的。
过滤器就像当于一个中间件,请求要经过过滤器,然后过滤器才去掉用Servlet,Servlet的响应也会被过滤器截获并作相应的处理。
Filter是一个接口,要写一个自己的Filter就只能实现Filter接口。
Filter也有自己的生命周期,他的生命周期和Servlet比较相似,也是会先调用init()方法,然后再调用核心的处理过滤的方法doFilter(),这个方法中可定义了过滤规则,然后是destory()方法销毁Filter对象。
dofilter(ServletRequest request,ServletResponse response,FilterChain chain)
这个是过滤的核心方法,FilterChain的方法doFilter(ServletRequest request, ServletResponse response)也就是用过滤后的请求调用资源的方法,如果不写这个方法,也就算不会去调用相应的资源。
Filter的配置
Filter的配置和Servlet相似。
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>alan.filter.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/protected/*</url-pattern>
<!--这里的url-pattern就是要过滤的Servlet的url-pattern-->
<dispatcher>request</dispatcher>
<dispatcher>forward</dispatcher>
<dispatcher>include</dispatcher>
<!--上面的三个是过滤的范围-->
</filter-mapping>
Servlet监听器
以下是3个Listener接口。
ServletRequestListener
HttpSessionListener
ServletContextListener
这三个监听器接口,分别监听Servlet中3种比较重要的对象的创建和销毁。这三个接口中分别有监听该对象创建和销毁事件的方法,服务器本身就是事件源。
listener的配置
<listener>
<listener-class>alan.servlet.listener.AlanContextListener</listener-class>
<!--listener-class也就是实现Listener接口的类-->
</listener>
Servlet中的重要对象(只针对应用)
数量 生命周期 是否线程安全
ServletContext 1 全局的 不安全
只有在应用关闭时才销毁 需要加同步访问
HttpSession 和用户的 局部的 不安全
数量相同 只在有效时间内存在 需要加同步访问
ServletRequest 多个 局部的 线程安全
(HttpServletRequest) 只在service()和doGet()
doPost()中存在
五、数据库连接池(了解)
数据库连接池,也就是在没有程序取连接时,可以事先创建好连接,连接池是一个运行在多线程环境下,提供数据库连接的程序,在程序使用完数据库连接后关闭数据库连接的动作不再是关闭连接的操作,而是把数据库连接放回连接池,也就是这个数据库连接已经是空闲状态,就可以供其他的程序取用了。
配置Tomcat服务器的数据源
在tomcat下的conf目录中的tomcat-users.xml文件中配置的是tomcat的用户
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="manager" description=""/>
<role rolename="admin"/><!--配置管理员-->
<user username="manager" password="123" fullName="" roles="manager"/>
<user username="admin" password="123" roles="admin"/>
<!--配置管理员的用户名和密码,并且标明是管理员roles="admin"-->
</tomcat-users>
<Resource
name="jdbc/oracle" 配置JDNI的名字
type="javax.sql.DataSource" 绑定资源的类型
password="sd0605"
driverClassName="oracle.jdbc.driver.OracleDriver" 驱动名
maxIdle="1"最大连接数
maxWait="-1"等待时间,配置为-1就是无限等待,只到有空闲连接为止
username="sd0605"
url="jdbc:oracle:thin:@192.168.0.39:1521:TARENADB"
maxActive="3" 最大活动连接数/>
以下的就是从连接池去取数据库连接的代码
public static Connection getConnection(String JNDIName)
{
Connection conn = null;
try
{
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
//这个是在tomcat下默认绑定Context的JNDIname
DataSource ds = (DataSource) envCtx.lookup(JNDIName);
conn = ds.getConnection();
} catch (NamingException ne)
{
ne.printStackTrace();
} catch (SQLException se)
{
se.printStackTrace();
}
return conn;
}