Web开发(一)--Servlet

来源:互联网 发布:暴雪防沉迷算法 编辑:程序博客网 时间:2024/05/18 13:08

Java Servlet是和平台无关的服务器端组件,功能是实现对客户端请求的响应。

Servlet组件运行在Servlet容器中,我们通常说的Servlet容器一般就指Tomcat服务器。

Servlet容器负责Servlet和客户的通信,以及调用Servlet的方法,Servlet和客户采用“请求/响应”的模式。

客户<---(请求/响应)--->Servlet容器<----(ServletRequest/ServletResponse)---->Servlet组件

Servlet可完成如下功能:

1.创建并返回基于客户请求的动态HTML页面

2.创建可嵌入到现有HTML页面中的部分HTML页面(Html片断)

3.与其他服务器资源进行通信,如数据库,基于Java的应用程序

Servlet其实就是一组Java程序,最顶层是接口Interface Servlet,Servlet组件实现该接口定义的方法,javax.servlet.Servlet接口

1、Servlet的创建与配置

在Eclipse中创建一个Dynamic Web Project,并且配置Tomcat服务器,选择next,最后可勾选web.xml的自动生成。

在src下创建package,并且创建HelloWorld类,实现Servlet接口,并且实现Servlet接口定义的方法,无参构造函数

public class HelloWorld implements Servlet{@Overridepublic void destroy() {System.out.println("destroy");}@Overridepublic ServletConfig getServletConfig() {System.out.println("getServletConfig");return null;}@Overridepublic String getServletInfo() {System.out.println("getServletInfo");return null;}@Overridepublic void init(ServletConfig arg0) throws ServletException {System.out.println("init");}@Overridepublic void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {System.out.println("service");}public HelloWorld() {System.out.println("HelloWorld constructor ...");}}
配置web.xml文件,在WebContent/WEB-INF下,配置HelloWorld类的Servlet和映射

<?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_3_0.xsd" id="WebApp_ID" version="3.0">  <display-name>ServletTest2</display-name>    <servlet>  <servlet-name>HelloWorld</servlet-name>  <servlet-class>com.cqupt.java.servlet.HelloWorld</servlet-class>  </servlet>  <servlet-mapping>  <servlet-name>HelloWorld</servlet-name>  <url-pattern>/hello</url-pattern>  </servlet-mapping></web-app>

配置两个元素:servlet和servlet-mapping

url-pattern元素中的/hello,其中"/"代表web应用的根目录,也就是http://localhost:8080/项目名/

右键项目,运行在服务器上,在Eclipse或系统的浏览器上,输入网址http://localhost:8080/项目名/配置的url-pattern

在这里是http://localhost:8080/ServletTest/hello,Eclipes显示的结果为:

HelloWorld constructor ...

init

service

无限制刷新网页时,每次只显示service

关闭服务器,显示destroy

这说明了Servlet的生命周期。

web.xml文件中servlet的配置和映射,如果只配置servlet,不配置映射servlet-mapping,并且设置为Tomcat启动时加载,会显示:

<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_3_0.xsd" id="WebApp_ID" version="3.0">  <display-name>ServletTest2</display-name>    <servlet>  <servlet-name>HelloWorld</servlet-name>  <servlet-class>com.cqupt.java.servlet.HelloWorld</servlet-class>  <load-on-startup>1</load-on-startup>  </servlet></web-app>

HelloWorld constructor ...

init

但不会显示service

注意:Servlet程序必须存储在"web应用程序目录\WEB-INF\classes\"目录中

2、Servlet的生命周期

使用Servlet时,我们不需要手动new类的实例,也不用手动调用方法,这一切都是Servlet容器帮我们完成的操作。

Servlet容器:运行Servlet、Jsp、Filter等的软件环境,可以来创建Servlet,并调用Servlet的相关生命周期方法。

由上节的HelloWorld可以看出,Servlet的生命周期:

1.构造方法:只被调用一次,只有在第一次请求Servlet时,才创建对应的Servlet实例,调用构造器。说明Servlet是单实例的!(单实例,就会存在线程安全问题,不推荐使用全局变量)

2.init方法:只被调用一次,在创建好实例后,立即被调用,用于初始化当前Servlet,init方法的形参有特殊的作用(ServletConfig类型的形参)。

3.service方法:被多次调用,每次请求都会调用service方法,实际用于响应请求的方法。

4.destroy方法:只被调用一次,在当前servlet所在的web应用被卸载前调用,用于当前Servlet所占用的资源。

这些方法都是Servlet容器负责调用。

3、load-on-startup

在servlet元素配置中,加入load-on-startup的配置标签,是为了,不需要请求,在Tomcat服务器启动时就加载该Servlet。

数值为负数,在请求时加载;数值为0和整数,在服务器启动时加载,并init初始化,并且,数值越小,越早被加载创建

  <servlet>  <servlet-name>HelloWorld</servlet-name>  <servlet-class>com.cqupt.java.servlet.HelloWorld</servlet-class>  <load-on-startup>0</load-on-startup>  </servlet>      <servlet>  <servlet-name>Second</servlet-name>  <servlet-class>com.cqupt.java.servlet.SecondServlet</servlet-class>  <load-on-startup>3</load-on-startup>  </servlet>       <servlet>  <servlet-name>Third</servlet-name>  <servlet-class>com.cqupt.java.servlet.ThirdServlet</servlet-class>  <load-on-startup>5</load-on-startup>  </servlet>
先创建加载HelloWorld,然后是Second,最后是Third

4、关于servlet-mapping

有关servlet-mapping的配置需注意两点

1.一个Servlet可以配置多个servlet-mapping,这样可以通过不同的url地址访问Servlet实例

2.url-pattern配置中使用通配符*只有两种合法的形式:

一种是 *.扩展名 的方法,例如 *.html,那么在访问web应用主目录 或者 aa.html 、.html时都可以请求到该Servlet

  <servlet>  <servlet-name>Third</servlet-name>  <servlet-class>com.cqupt.java.servlet.ThirdServlet</servlet-class>  <load-on-startup>5</load-on-startup>  </servlet>  <servlet-mapping>  <servlet-name>Third</servlet-name>  <url-pattern>*.html</url-pattern>  </servlet-mapping>
访问 :

web主目录:http://localhost:8080/ServletTest/ 

http://localhost:8080/ServletTest/.html

http://localhost:8080/ServletTest/aa.html都可以得到Servlet 的响应。

第二种是以正斜杠/开头,并以 /* 结尾

  <servlet>  <servlet-name>Third</servlet-name>  <servlet-class>com.cqupt.java.servlet.ThirdServlet</servlet-class>  <load-on-startup>5</load-on-startup>  </servlet>  <servlet-mapping>  <servlet-name>Third</servlet-name>  <url-pattern>/*</url-pattern>  </servlet-mapping>
其他例如 /*.action 都不合法。

5、初始化参数及ServletConfig类

Servlet配置时,可以给需要的Servlet配置初始化参数,配置方法:在servlet标签下使用init-param标签

  <servlet>  <servlet-name>HelloWorld</servlet-name>  <servlet-class>com.cqupt.java.servlet.HelloWorld</servlet-class>    <!-- init-param 标签必须放在load-on-startup标签之前 ,否则有错-->  <init-param>  <!-- 参数名 -->  <param-name>user</param-name>  <!-- 参数值 -->  <param-value>root</param-value>  </init-param>  <init-param>  <param-name>password</param-name>  <param-value>1234</param-value>    </init-param>    <load-on-startup>0</load-on-startup>  </servlet>  <servlet-mapping>  <servlet-name>HelloWorld</servlet-name>  <url-pattern>/hello</url-pattern>  </servlet-mapping>
注意:init-param 标签必须放在load-on-startup标签之前 ,否则有错

那么如何在Servlet类中获取呢,关键在ServletConfig类,Servlet的init方法的形参就是ServletConfig类型

可以通过Servlet的init方法获取配置的初始化参数:

1.使用ServletConfig的getInitParameter(参数名)获取

@Overridepublic void init(ServletConfig config) throws ServletException {System.out.println("init get init-param");String user = config.getInitParameter("user");System.out.println("user:"+user);String password = config.getInitParameter("password");System.out.println("password:"+password);}

2.使用ServletConfig类的getInitParameterNames()获取所有参数名的Enumeration集合对象,再根据参数名获取参数值

@Overridepublic void init(ServletConfig config) throws ServletException {System.out.println("init get init-param");Enumeration<String> names = config.getInitParameterNames();while(names.hasMoreElements()){String name = names.nextElement();System.out.println(name+":"+config.getInitParameter(name));}}
也可以使用getServletName()获取Servlet的名字

System.out.println(config.getServletName());

还可以使用getServletContext获取ServletContext对象,经常使用。

ServletContext servletContext = config.getServletContext();

6、ServletContext

ServletContex同ServletConfig类一样,是Servlet中经常使用且很重要的类。

ServletContext对象代表当前Web应用:可以认为ServletContext是当前web应用的大管家,可以从中获取关于Web应用的各种信息。

1.设置当前Web应用的初始化参数,直接在web-app标签下配置context-param标签即可

  <!-- 配置当前web应用的初始化参数 -->  <context-param>  <param-name>driver</param-name>  <param-value>com.mysql.jdbc.Driver</param-value>  </context-param>  <context-param>  <param-name>jdbcUrl</param-name>  <param-value>jdbc:mysql:///test</param-value>  </context-param>

通过ServletContext配置的初始化参数可以被所有的Servlet获取,而Servlet配置的初始化参数只能被其自身获取。

通过getInitParameter(参数名)和getInitParameterNames()获取

@Overridepublic void init(ServletConfig config) throws ServletException {System.out.println("init ...");ServletContext servletContext = config.getServletContext();String driver = servletContext.getInitParameter("driver");System.out.println(driver);Enumeration<String> names = servletContext.getInitParameterNames();while(names.hasMoreElements()){String name = names.nextElement();String value = servletContext.getInitParameter(name);System.out.println(value);}}


2.获取当前Web应用的某一个文件在服务器上的绝对路径,而不是部署前的路径。

使用getRealPath(String path),path是根目录下的路径文件,以/开始

//note.txt在WebContent/下,获取的不是部署前的路径String realPath = servletContext.getRealPath("/note.txt");System.out.println(realPath);//D:\java\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\ServletTest\note.txt

3.获取当前web应用的名称

String webName = servletContext.getContextPath();System.out.println(webName);//输出:/ServletTest
输出Web应用的名称,不是项目的名称,默认的Web名称是项目的名称,但是后期在配置服务器发布web应用时,经常会改变,通过这个方法可以动态获取到Web应用的名称。


4.获取文件输入流,getResourceAsStream(String path),其中path是当前Web应用的根目录开始的:"/"

try{ClassLoader classLoader = getClass().getClassLoader();InputStream prop = classLoader.getResourceAsStream("jdbc.properties");System.out.println(prop);}catch(Exception e) {e.printStackTrace();}try{//使用Servlet获取文件输入流,文件路径必须是从web应用开始//而在项目src下的所有文件都部署在web应用的/WEB-INF/classes/目录下//InputStream in = servletContext.getResourceAsStream("jdbc.properties");//null获取不到InputStream in = servletContext.getResourceAsStream("/WEB-INF/classes/jdbc.properties");System.out.println(in);}catch(Exception e) {e.printStackTrace();}

5.和Attribute相关的方法,后续。

7、HTTP协议

HTTP协议是超文本传输协议,是TCP/IP协议族的应用层协议,负责浏览器与服务器之间数据交换的过程,以及数据本身的格式。

HTTP协议是无状态的,每次网页的请求,都必须建立连接----发送请求-----返回数据-----断开连接,之所以服务器可以跟踪客户的网页访问,是Session起的作用(后续)

每次连接只处理一个请求和响应。

请求消息的结构:一个请求行,若干消息头,以及实体内容,消息头和实体内容之间要用空行隔开

响应消息的结构:一个状态行,若干消息头,以及实体内容,同样,消息头和实体内容之间要用空行隔开


请求方式有两种:GET请求和POST请求

GET请求,将参数附加在URL后,以键值对的方式,传送的数据是有限制的,一般在1kb以下

http://localhost:8080/ServletTest/loginServlet?user=bbb&password=123&submit=submit

POST请求,把参数插入在请求体里,传送的数据量比GET请求传送的多。

GET请求

1.在浏览器中输入URl地址或者单击网上的一个超链接时,浏览器发出的HTTP请求方法就是GET

2.如果网页的form表单指定了请求方法为GET,浏览器提交这个表单时,生成的HTTP请求消息的请求方式也是GET

3.使用GET请求为WEB服务器传参数格式:url?参数名1=参数1&参数名2&参数2

http://localhost:8080/ServletTest/loginServlet?user=bbb&password=123

4.使用GET请求传递的数据在1k以下,传递参数一般够用。

POST请求

1.网页表单form指定的请求方式为post,生成的HTTP请求使用POST方法

2.POST请求将form表单提交的数据作为HTTP消息的请求实体发送给WEB服务器,传递的数据比GET方法要大得多。

提交文件时,必须使用POST请求

8、service方法

service方法是响应请求的实际方法,每次客户端对Servlet的请求都调用该Servlet的service方法。

public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {}

service方法可以获取到请求的信息,也可以对请求作出响应,主要通过其参数ServletRequest和ServletResponse对象

ServletRequest和ServletResponse是Servlet容器实现的,目的是容器将接收到的HTTP请求封装到ServletRequest中传递给Servlet组件,解析ServletResponse中的响应转为HTTP响应。

客户<---(请求/响应)--->Servlet容器<----(ServletRequest/ServletResponse)---->Servlet组件

ServletRequest封装了请求信息,从中可以获取到任何的请求信息;

ServletResponse封装了响应信息,如果想给用户什么响应,可调用该类型对象的方法;

这两个接口的实现类,都是服务器给与实现的,并在服务器调用service方法时传入

ServletRequest

1.获取请求参数:
String getParameter(String name):根据参数名获取参数值,若请求有参数有多个值,此方法只能获取第一个提交的值
String[] getParameterValues(String name):根据参数名,返回请求参数名对应的参数值字符串数组
Enumeration getParameterNames():返回参数名对应的Enumeration集合,类似于ServletContext和ServletConfig中的方法
Map getParameterMap():返回请求参数的键值对:key参数名,value:参数值,String数组类型
表单,提价给loginServlet
<form action="loginServlet" method="get">user:<input type="text" name="user"/>password:<input type="text" name="password"/><br/><br/>interesting:<input type="checkbox" name="interesting" value="reading"/>reading<input type="checkbox" name="interesting" value="game"/>game<input type="checkbox" name="interesting"/ value="movie">movie<input type="checkbox" name="interesting"/ value="tv">tv<input type="checkbox" name="interesting"/ value="running">running<input type="checkbox" name="interesting" value="sleep"/>sleeping<input type="submit" name="submit" value="submit"/></form>
/loginServlet地址的映射
  <servlet>  <servlet-name>loginServlet</servlet-name>  <servlet-class>com.cqupt.java.servlet.LoginServlet</servlet-class>  </servlet>  <servlet-mapping>  <servlet-name>loginServlet</servlet-name>  <url-pattern>/loginServlet</url-pattern>  </servlet-mapping>
LoginServlet类
@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {System.out.println("请求来了");//根据参数名获取参数值String user = request.getParameter("user");System.out.println("user:"+user);//根据一个参数名获取多个值的参数值String[] params = request.getParameterValues("interesting");for(String param : params){System.out.println("intersting:"+param);}//intersting:reading//intersting:game//intersting:sleepMap<String,String[]> maps= request.getParameterMap();for(Map.Entry<String,String[]> map:maps.entrySet()){System.out.println(map.getKey()+":"+Arrays.asList(map.getValue()));}//user:[wwa]//password:[12321]//interesting:[reading, game, sleep]//submit:[submit]}
2.获取请求的URI,统一资源标示符,在这里是站点下的请求页面的资源地址
使用HttpServletRequest的getRequestURI()方法。
HttpServletRequest是ServletRequest的子接口,针对HTTP请求所定义,里边包含了大量的有关HTTP请求相关的方法
3.获取请求方式getMethod()
4.获取GET请求的参数字符串 getQueryString()
5.获取Servlet的映射路径:getServletPath()
@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {//HttpServletRequest是ServletRequest的子接口,实现类可以为HttpServletRequest,获取更多方法HttpServletRequest httpServletRequest = (HttpServletRequest)request;//1.获取请求的uriString uri = httpServletRequest.getRequestURI();System.out.println(uri);//输出:/ServletTest/loginServlet//2.获取请求的提交方法:POST or GETString method = httpServletRequest.getMethod();System.out.println(method);//GET//3.若是一个GET请求,获取请求参数对应的那个字符串,即请求?后的字符串,若是POST方式,则获取值为nullString query = httpServletRequest.getQueryString();System.out.println(query);//user=wwa&password=12321&interesting=reading&interesting=game&interesting=sleep&submit=submit//4.获取servlet的映射路径,就是配置在servlet-mapping的url-patternString servletPath = httpServletRequest.getServletPath();System.out.println(servletPath);//  /loginServlet}

ServletResponse

1.getWriter方法,返回PrintWriter对象,利用该对象的print方法,可以向浏览器页面打印信息。
2.setContentType(String type),可以设置响应的内容类型,当参数是"application/msword"时,浏览器输入网址,会显示下载文档,没有页面信息
3.void sendRedirect(String location):请求的重定向,HttpServletResponse中的方法,非常重要
HttpServletResponse中还有很多关于HTTP协议响应的很多方法。
@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {//2.设置响应的内容类型response.setContentType("application/msword");//1.getWriter获取PrintWriter对象,该对象的print方法,可以把参数直接打印在浏览器页面上。PrintWriter pw=response.getWriter();pw.println("This is Servlet!");}

9、GenericServlet

前边讲到Servlet接口和ServletConfig接口,在Servlet的init方法中,参数是ServletConfig的对象。那么每次在获取Servlet的配置信息时,必须调用init方法,得到ServletConfig对象。这样,比较麻烦,所以,为了更直观的使用Servlet接口,就产生了GenericServlet抽象类,该类其实是对Servlet以及ServletConfig的封装,方便获取信息。
public abstract class GenericServlet implements Servlet, ServletConfig,        java.io.Serializable {    private static final long serialVersionUID = 1L;    private transient ServletConfig config;    public GenericServlet() {    }    @Override    public void destroy() {    }    @Override    public String getInitParameter(String name) {        return getServletConfig().getInitParameter(name);    }       @Override    public Enumeration<String> getInitParameterNames() {        return getServletConfig().getInitParameterNames();    }    @Override    public ServletConfig getServletConfig() {        return config;    }    @Override    public ServletContext getServletContext() {        return getServletConfig().getServletContext();    }    @Override    public String getServletInfo() {        return "";    }    @Override    public void init(ServletConfig config) throws ServletException {        this.config = config;        this.init();    }    public void init() throws ServletException {        // NOOP by default    }    public void log(String msg) {        getServletContext().log(getServletName() + ": " + msg);    }    public void log(String message, Throwable t) {        getServletContext().log(getServletName() + ": " + message, t);    }    @Override    public abstract void service(ServletRequest req, ServletResponse res)            throws ServletException, IOException;    @Override    public String getServletName() {        return config.getServletName();    }}
其中,service方法为抽象方法,所有根据特定协议实现的Servlet类,都必须实现覆盖并实现自己的service方法。

10、HttpServlet

HtttpServlet类是针对HTTP协议实现的Servlet类,继承自GenericServlet。
HttpServlet的实现基于HttpServletRequest和HttpServletResponse两个接口,分别继承自ServletRequest和ServletResponse两个接口。

可以看部分代码
    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);    }}

实现了GenericServlet的service方法,直接将ServletRequest和ServletResponse强转为HttpServletRequest和HttpServletResponse,
并调用重载的service(HttpServletRequest, HttpServletResponse)方法,在该方法中获取请求方式,httpServletRequest.getMethod(),
根据请求方法,创建了doXXX()方法,入doGet()和doPost()方法
实际开发中,只需继承HttpServlet,并根据请求,复写doXXX()方法。

好处:
直接针对Http协议,针对性的覆盖doXXX()方法即可,使用HttpServletRequest和HttpServletResponse,不需要强转。



0 0
原创粉丝点击