Java Servlet基础
本章将使用javax.servlet.http包中的类。该包不包含在JDK的核心类库中,因此需将Tomcat安装目录lib子目录中的servlet-api.jar文件复制到JDK根目录下jre/lib/ext中。
为了便于理解,我们先简单提一下MVC模式,这个模式在JAVA里也有提过,是一种被广泛使用的一种设计模式。
MVC模式的核心思想是有效组合“模型(model)”、“视图(view)”、“控制器(controller)”。是一种先进的设计模式。
model:用于存储数据的对象。
view:向控制器提交所需数据、显示模型中的数据。
controller:负责具体的业务逻辑操作,即控制器根据视图提出的要求对数据做出处理,将有关结果存储到模型中,并负责让模型和视图进行必要的交互,当模型中的数据变化时,让视图更新显示。
从面向对象的角度看,MVC结构可以使程序更具有对象化特征,也更容易维护(低耦合)。
我们上一章学的bean和这章即将学的servlet,一个是model部分,一个是controller部分,虽然某些功能有重叠,但是这是需要分层所必须的,我们需要清楚,我们这章使用servlet完成的很多任务,大部分都是上一章类似的,并且可以用上一章的方法实现,但是bean实际上是用来做数据存储的,其他操作只是他的“副产品”,而且servlet的功能会比bean强大得多(也麻烦的多emmm)。
java Servlet的核心思想是在服务器端创建能响应用户请求的对象。
1.Servlet类
就是编写一个特殊的子类,这个特殊的类就是javax.servlet.http包中的HttpServlet类。HttpServlet类实现了Servlet接口,实现了响应用户的方法。HttpServlet类的子类被习惯地称为作一个Servlet类,这样的类创建的对象习惯上被称作一个servlet。
2.保存字节码文件
Servlet类的字节码文件和bean的字节码文件一样,都应该保存到以classes为根目录下的对应目录中。
3.编写web.xml文件
和bean不同的是,我们需要编写部署文件,这样Tomcat服务器才会按客户的请求使用Servlet字节码文件创建对象。
web.xml文件在WEB-INF文件下,先来简单学习一些xml标记,比如下面这个?。
<servlet> <servlet-name>hello</servlet-name> <servlet-class>JavaServlet.ServletTest</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/lookHello</url-pattern> </servlet-mapping>
<servlet>标记及其子标记
该标记 需要两个子标记:<servlet-name>和<servlet-class>,其中<servlet-name>标记的内容是服务器创建的servlet的名字,<servlet-class>标记的内容指定服务器用那个Servlet类创建servlet。
<servlet-mapping>标记及其子标记
<servlet-mapping>标记需要两个子标记:<servlet-name>和<url-pattern>,其中<servlet-name>标记的内容是服务器创建的servlet名字(和上面的名字相同),<url-pattern>标记用来指定用户用怎样的url格式来请求servlet。
比如上栗中,名字是hello,字节码文件存放在./classes/JavaServlet/ServletTest.class中,访问./lookHello 即可访问该Servlet类。
example5_1.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY ><Font size=3> <FORM action="lookHello" method=post> <BR>输入圆的半径: <Input type="text" name="radius"> <Input type="submit" value="提交"> </FORM> </Font></BODY></HTML>
ServletTest.java
package JavaServlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ServletTest extends HttpServlet { public void init(ServletConfig config) throws ServletException { super.init(config); } public void service(HttpServletRequest request,HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=GB2312"); PrintWriter out=response.getWriter(); out.println("<html><body>"); String str=request.getParameter("radius"); //获取客户提交的信息 double r=0; try{ r=Double.parseDouble(str); if(r>=0) { out.print("<BR>半径是 "+r+" 的圆的面积:"); out.print("<BR>"+Math.PI*r*r); } else { out.print("<BR>圆的半径不可以是负数:"+r); } } catch(NumberFormatException e) { out.print("<H1>请输入数字字符! </H1>"); } out.println("</body></html>"); } }
我们右键编辑web.xml(不要双击,否则会打开xml文件)。
web.xml(添加)
<servlet> <servlet-name>hello</servlet-name> <servlet-class>JavaServlet.ServletTest</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/lookHello</url-pattern> </servlet-mapping>
运行结果:
我们发现,上面地址栏是lookHello,并且执行了ServletTest.java的字节码的执行结果。
同样,我们可以在URL里直接输入参数访问lookHello
所以我们这里既可以向lookHello提交表单(form),也可以直接<a href=”lookHello??radius=10> 超链接到该类,效果都是一样的。
注意:对所有的字节码文件进行更改、对web.xml文件进行更改都需要重启服务器。
(如果你在跟我做,较新版本的Tomcat在web.xml做出更改之后可以重新加载,所以节省操作不用重启,但是书上仍然要求重启。)
servlet的创建与运行
用户可以根据web.xml部署文件来请求服务器创建并运行一个servlet。如果服务器没有名字为hello的servlet,服务器就会根据web.xml文件中的<servlet>的class指定的servlet类创建一个名字为hello的servlet对象。因此对web.xml的更改或是对字节码的更改必须重启服务器。
servlet类可以使用getServletName()方法返回配置文件中的<servlet-name>标记给出的servlet的名字。
当用户请求服务器运行一个servlet时,必须根据web.xml文件中的<servlet-mapping>标记的子标记<url-pattern>指定的格式输入请求。
servlet对象的生命周期
一个servlet的生命周期主要有下列3个过程组成:
(1)初始化servlet,servlet第一次被请求加载时,服务器初始化这个servlet,即创建一个servlet,这个servlet调用init()方法完成必要的初始化工作。
(2)新诞生的servlet再调用service【servlet类中的方法】方法相应用户的请求。
init方法只被调用一次,即在servlet第一次被请求加载时调用该方法。当后续的用户请求servlet服务时,Web服务将启动一个新的线程,在该线程中,servlet调用service方法响应用户的请求。
init方法:首次请求时被调用。
service方法:当servlet成功创建和初始化后,调用servlet服务器会将两个参数传递给该方法:一个是HttpServletRequest类型的对象,该对象封装了用户的请求信息;另一个是HttpServletResponse类型的对象,该对象用来响应用户的请求。
destroy方法:当服务器终止服务时,该方法会被执行,用来销毁servlet。
init方法只会被调用一次(当然destroy也是),但是service可以被调用很多次,每当有新用户访问servlet时,服务器都会为用户分配一个全新的线程并调用该方法。
4.共享变量
因为每个用户都调用Servlet的service方法,所以
example5_4.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY ><Font size=5> <A Href="lookPI" >参与计算PI的值<A> </BODY></HTML>
computePI.java
package JavaServlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class computePI extends HttpServlet { double sum=0,i=1,j=1; int number=0; public void init(ServletConfig config) throws ServletException {super.init(config); } public synchronized void service(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=GB2312"); PrintWriter out=response.getWriter(); out.println("<html><body>"); number++; sum=sum+i/j; j=j+2; i=-i; out.println("servlet:"+getServletName()+"已经被请求了"+number+"次"); out.println("<BR>现在PI的值是:"); out.println(4*sum); out.println("</body></html>"); } }
web.xml(增加)
<servlet> <servlet-name>PI</servlet-name> <servlet-class>JavaServlet.computePI</servlet-class> </servlet> <servlet-mapping> <servlet-name>PI</servlet-name> <url-pattern>/lookPI</url-pattern> </servlet-mapping>
我们看到如果你把变量放到整个Servlet类的成员变量可以被所有访问该页面的用户所共享。
这个值随着访问次数的增加会越来越接近PI。
5.doGet和doPost方法
这两个方法是用来处理用户的请求并作出响应的方法。
我们知道,当用户访问Servlet类时,服务器会为该用户分配一个全新的线程来调用service方法,但是实际上这里service方法的功能是检查HTTP的请求类型(get或者post),并在service方法中根据请求方式的不同调用上述两种方法,所以我们可以直接复写doGet和doPost两个方法完成对两种请求的不同响应。
当然这种方法可以增加响应的灵活性并降低服务器的负担,如果对两种请求方式作出的响应相同,只需要在doGet方法中调用doPost方法或者在doPost方法中调用doGet方法即可。
example5_5.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY ><Font size=2> <P>输入一个数,提交给servlet(Get方式): <FORM action="lookSquare" method=get> <Input Type=text name=number> <Input Type=submit value="提交"> </FORM> <P>输入一个数,提交给servlet(Post方式): <FORM action="lookSquare" method=post> <Input Type=text name=number> <Input Type=submit value="提交"> </FORM> </BODY></HTML>
GetSquareOrcubin.java
package JavaServlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class GetSquareOrCubic extends HttpServlet { public void init(ServletConfig config) throws ServletException {super.init(config); } public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { response.setContentType("text/html;charset=GB2312"); PrintWriter out=response.getWriter(); out.println("<html><body>"); String number=request.getParameter("number"); //获取客户提交的信息 double n=0; try{ n=Double.parseDouble(number); out.print("<BR>"+number+"的平方是:"); out.print("<BR>"+n*n); } catch(NumberFormatException e) { out.print("<H1>请输入数字字符! </H1>"); } out.println("</body></html>"); } public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { response.setContentType("text/html;charset=GB2312"); PrintWriter out=response.getWriter(); out.println("<html><body>"); String number=request.getParameter("number"); //获取客户提交的信息 double n=0; try{ n=Double.parseDouble(number); out.print("<BR>"+number+"的立方是:"); out.print("<BR>"+n*n*n); } catch(NumberFormatException e) { out.print("<H1>请输入数字字符! </H1>"); } out.println("</body></html>"); } }
web.xml(添加)
<servlet> <servlet-name>showSquareOrCubic</servlet-name> <servlet-class>JavaServlet.GetSquareOrCubic</servlet-class> </servlet> <servlet-mapping> <servlet-name>showSquareOrCubic</servlet-name> <url-pattern>/lookSquare</url-pattern> </servlet-mapping>
我们可以直观的看出访问方式的不同导致服务器响应的不同。
6.重定向与转发
重定向的功能是将用户从当前页面或servlet定向到另一个JSP页面或Servlet;(让你到另一个页面)
转发的功能是将用用户对当前JSP页面或Servlet的请求转发给另一个JSP页面或Servlet。(把你提交的表单给别人一份)
1.sendRedirect方法
重定向方法仅仅是将用户从当前页面或Servlet定向到另一个JSP页面或者Servlet,但不能将用户对当前页面或Servlet的请求转发给所定向的资源,也就是说,重定向的目标或者页面无法使用request获取用户提交的数据。
2.RequestDispatcher对象
RequestDispatcher对象可以把用户对当前JSP页面或Servlet的请求转发给另一个JSP页面或Servlet,而将用户对当前JSP页面或Servlet的请求和响应传递给转发到的JSP页面或Servlet。也就是说,当前页面所要转发到的目标页面或Servlet可以使用request获取用户提交的数据。
方法:
1.得到RequestDispatcher对象。
在当前页面调用getRequestDispatcher(String path);该方法返回一个RequestDispatcher对象,其中参数path是目的页面或Servlet。
2.转发
在1中获取的对象下调用.forward(request,response);
example5_6.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY ><Font size=2> <FORM action="verifyYourMessage" method=post> 输入姓名:<Input Type=text name=name> <BR>输入年龄:<Input Type=text name=age> <BR><Input Type=submit value="提交"> </FORM></BODY></HTML>
example3_6.jsp(名字打错了emmm就不改了)
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY ><Font size=2> <% String name=request.getParameter("name"); String age=request.getParameter("age"); out.print(name+" "+age); %> </FORM></BODY></HTML>
Verify.java
package JavaServlet; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class Verify extends HttpServlet { public void init(ServletConfig config) throws ServletException {super.init(config); } public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { String name=request.getParameter("name"); //获取客户提交的信息 String age=request.getParameter("age"); //获取客户提交的信息 if(name.length()==0||name==null) { response.sendRedirect("example5_6.jsp"); //重定向 } else if(age.length()==0||name==null) { response.sendRedirect("example5_6.jsp"); //重定向 } else if(age.length()>0) { try { int numberAge=Integer.parseInt(age); if(numberAge<=0||numberAge>=150) { response.sendRedirect("example5_6.jsp"); } else { RequestDispatcher dispatcher= request.getRequestDispatcher("example3_6.jsp"); dispatcher.forward(request, response); //转发 } } catch(NumberFormatException e) { response.sendRedirect("example5_6.jsp"); } } } public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { doPost(request,response); } }
web.xml(添加)
<servlet> <servlet-name>verify</servlet-name> <servlet-class>JavaServlet.Verify</servlet-class> </servlet> <servlet-mapping> <servlet-name>verify</servlet-name> <url-pattern>/verifyYourMessage</url-pattern> </servlet-mapping>
我们看到,如过是又一个文本框没有填写,则会被重定向回当前页面,如果两个都填写了,则请求会被转发到example3_6.jsp,并显示传过去的数字(尽管此时URL显示的是当前Servlet)。
课后题:
1.Servlet对象是在服务器端还是客户端被创建?
· 服务器端。
2.Servlet对象被创建后将先调用init方法还是service方法?
· 先调用init完成相应的初始化操作,然后调用service方法相应操作。
3.“Servlet第一次被请求加载时调用init方法。当后续的客户请求Servlet对象时, Servlet对象不再调用init方法”,这样的说法是否正确?
· 正确。
4.假设创建Servlet的类是tom.jiafei.Dalian,创建的Servlet对象的名字是myservlet,应当怎么配置web.xml文件?
<servlet> <servlet-name>myservlet</servlet-name> <servlet-class>tom.jiafei.Dalian</servlet-class> </servlet> <servlet-mapping> <servlet-name>myservlet</servlet-name> <url-pattern>/Dalian</url-pattern> </servlet-mapping>
5.如果Servlet类不重写service方法,那么应当重写哪两个方法?
· doPost()和doGet()
6.HttpServletResponse类的sendRedirect方法和RequestDispatcher类的forward方法有何不同?
· 一个是重定向,一个是转发。重定向的功能是将用户从当前页面或servlet定向到另一个JSP页面或Servlet;转发的功能是将用用户对当前JSP页面或Servlet的请求转发给另一个JSP页面或Servlet。
7.Servlet对象怎么获得用户的会话对象?
· 在doGet()或doPost()方法中使用获取当前会话对象.HttpSession session=request.getSession(true);
一个用户在不同的Servlet中获取的session对象是完全相同的,不同的用户的session对象互不相同。
0 条评论