什么是servlet
Servlet(Server Applet)是Java Servlet的简称,是小服务程序或服务连接器,是用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容.
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
第一个servlet
Sun公司在其API中提供了一个servlet接口,用户若想开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
编写一个Java类,实现servlet接口。
把开发好的Java类部署到web服务器中。
首先,我们要编写一个类,实现Servlet接口:
方法介绍
init( )
Servlet第一次被请求,Servlet容器就会开始调用这个方法初始化一个Servlet对象,但是这个方法在后续请求中不会在被Servlet容器调用。我们可以利用init( )方法来执行相应的初始化工作。调用这个方法时,Servlet容器会传入一个ServletConfig对象进来从而对Servlet对象进行初始化。
service( )
每当请求Servlet时,Servlet容器就会调用这个方法。
第一次请求时,Servlet容器会先调用init(),然后调用service( ),在后续的请求中,Servlet容器只调用service方法。
destory
当要销毁Servlet时,Servlet容器就会调用这个方法,在卸载应用程序或者关闭Servlet容器时,就会发生这种情况,一般在这个方法中会写一些清除代码。
另外两个:
getServletInfo( ),这个方法会返回Servlet的一段描述,可以返回一段字符串。
getServletConfig( ),这个方法会返回由Servlet容器传给init()方法的ServletConfig对象。
生命周期
Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。
在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。
实例化-->初始化-->服务->销毁
出生:(实例化-->初始化)第一次访问Servlet就出生(默认情况下)
活着:(服务)应用活着,servlet就活着
死亡:(销毁)应用卸载了servlet就销毁。
如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
举例:
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>org.apache.catalina.servlets.InvokerServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
l用途:为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据。
xml
由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
<servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:
编写文件中的<servlet>\<servlet-mapping>节点。
<web-app>
<servlet>
<servlet-name>AnyName</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/demo/hello.html</url-pattern>
</servlet-mapping>
</web-app>
网址找到文件的过程就是这样的啦
至此,servelet访问过程大体完成:
Servlet 接口实现类
Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet、HttpServlet。
Servlet --> GenericServlet --> HttpServlet (继承HttpServlet)
HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。
HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。
ServletRequset接口
Servlet容器对于接受到的每一个Http请求,都会创建一个ServletRequest对象,并把这个对象传递给Servlet的Sevice( )方法。其中,ServletRequest对象内封装了关于这个请求的许多详细信息。
让我们来看一看ServletRequest接口的部分内容:
public interface ServletRequest {
int getContentLength();//返回请求主体的字节数
String getContentType();//返回主体的MIME类型
String getParameter(String var1);//返回请求参数的值
}
其中,getParameter是在ServletRequest中最常用的方法,可用于获取查询字符串的值。
ServletResponse接口
javax.servlet.ServletResponse接口表示一个Servlet响应,在调用Servlet的Service()方法前,Servlet容器会先创建一个ServletResponse对象,并把它作为第二个参数传给Service()方法。ServletResponse隐藏了向浏览器发送响应的复杂过程。
让我们也来看看ServletResponse内部定义了哪些方法:
public interface ServletResponse {
String getCharacterEncoding();
String getContentType();
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentType(String var1);
void setBufferSize(int var1);
int getBufferSize();
void flushBuffer() throws IOException;
void resetBuffer();
boolean isCommitted();
void reset();
void setLocale(Locale var1);
Locale getLocale();
}
其中的getWriter方法,它返回了一个可以向客户端发送文本的的Java.io.PrintWriter对象。默认情况下,PrintWriter对象使用ISO-8859-1编码(该编码在输入中文时会发生乱码)。
在向客户端发送响应时,大多数都是使用该对象向客户端发送HTML。
还有一个方法也可以用来向浏览器发送数据,它就是getOutputStream,从名字就可以看出这是一个二进制流对象,因此这个方法是用来发送二进制数据的。
在发送任何HTML之前,应该先调用setContentType()方法,设置响应的内容类型,并将“text/html”作为一个参数传入,这是在告诉浏览器响应的内容类型为HTML,需要以HTML的方法解释响应内容而不是普通的文本,或者也可以加上“charset=UTF-8”改变响应的编码方式以防止发生中文乱码现象。
跳转
我们的网页可能会跳转到其他页面,怎么实现这个功能呢?有两种方法:
转发
重定向
他俩是什么意思呢。
举个例子:a给b打电话,聊了一会说,我找c。
这时候,b说,行,我给你转接到c手里,这就是转发。
这时候,b说,行,我给你c的电话号码,你自己打过去吧,然后a挂了电话给c打,这叫重定向。
•请求转发
–request.getRequestDispatcher(" targetURL").forward(request, response);
•请求重定向
–response.sendRedirect("targetURL")
转发是把请求转发给别人,重定向是发回给用户,用户发一个新的请求给新的servlet。
转发:
是服务器跳转,是同一个请求在服务器端传递,浏览器根本不知道发生了转发操作。
重定向:
是给用户一个新的地址,用户根据新的地址发送新的请求。
总结异同点:
相同点:都实现了跳转
不同点:
1、语法不同(废话)
2、跳转后,转发可以得到request里的内容,重定向得不到
3、地址栏路径不同,转发地址不变,重定向就是新的地址了。
4、原理不同,转发:就一个请求,重定向:两个
5、效率:转发>重定向(显而易见)
6、跳转范围不同:转发只能是当前项目,重定向随便
7、
写的路径不同:
转发不能写绝对路径,重定向可以;
转发写根路径不写上下文路径,代表当前项目根目录,重定向根路径需要写上下文路径,代表当前服务器;
建议都是用根路径。
8、转发会导致表单的重复提交,重定向不会。(刷新的话,转发是之前的地址,刷新就。。。)
9、转发不经过过滤器,重定向会经过(可以设置,让转发经过)
跳转方式的选择
必须的四种:
希望前后共享request,转发。
跳转到同一个WEB-INF目录下,只能转发。(因为不能直接访问里面,只能转发请求进去,重定向本质就是发了一个新请求,不可能)
跳到不同项目,只能重定向。。。(废话)
使用cookie存数据后要跳,只能重定向。转发后还没有呢。。(这个以后再说)
更优的四种:
转发效率高,尽量使用转发
但是使用转发需要解决重复提交表单问题。
注销之后一般用重定向
连续表单页面应使用重定向,尽量避免属性冲突
总体流程的例子
前三行为了解决中文乱码问题
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求编码格式
req.setCharacterEncoding("utf-8");
//设置相应编码格式
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//获取请求信息
//处理请求信息
FlowerService fs=new FlowerServiceImpl();
List<Flower> lf=fs.getFlowerInfoService();
//响应结果
req.setAttribute("lf", lf);
req.getRequestDispatcher("/show.jsp").forward(req, resp);
}