Servlet接口基本知识

来源:互联网 发布:高级编程语言培训 编辑:程序博客网 时间:2024/06/07 19:13

Servlet接口:
 Servlet是一种实现了javax.servlet.Servlet接口的类。
 Servlet接口规定了特定的方法来处理特定的请求,作为开发者只需要去实现Servlet的相关方法,这样当用户访问Web程序的时候 Tomcat会调用相应的方法来完成业务的处理。
 Servlet的规范是建立在HTTP规范的基础之上的。
一般用到的访问方式:
 1,GET表示查询信息(非隐私、小量的数据提交)
 2,POST表示提交信息(隐私、大量的数据提交)
当浏览器以xxx的方式来访问网络得程序的时候,Servlet会执行形如void doXxx(HttpServletRequest request,HttpServletResponse response)
Servlet还有一个方法是用来返回文档的最后修改时间的
 long getLastModified(HttpServletRequest request),它默认返回的是-1,表示文档永远是最新的
Web程序文件结构:
 /    ----这个是Web应用的根目录
 |--WEB-INF   ----Tomcat会隐藏这个目录下的文件,这样通过浏览器是无法直接访问的
  |--web.xml  ----Web程序最主要的配置文件
  |--classes  ----class类文件是放在这个文件下面的
  |--lib   ----jar文件都发在这个文件下面

Servlet的编写:
 可以直接实现Servlet接口,不过不推荐因为需要实现的方法太多
 javax.servlet.http.HttpServlet类已实现了Servlet接口中的所有方法,编写Servlet类可以直接继承这个类并覆盖相应的处理方法即可,一般来说是需要覆盖doGet(),doPost()

如果以get方式访问页面会执行这个函数(doGet)
执行doGet前会先执行getLastModified,如果发现这个的返回值与上一次的相同则会认为这个
文档是没有更新过的这个时候浏览器会使用缓存而不会执行后续的doGet
如果getLastModified返回的是-1则认为文档时刻是更新的,则总是会执行doGet的内容

以POST方式访问页面时会执行这个函数(doPost)
执行这个函数前是不是去执行getLastModified来做判断的

配置Servlet:
 在有了Servlet类后还需要在web.xml当中对servlet进行配置
<servlet>
 <servlet-name>FirstServlet</servlet-name>
 <servlet-class>com.xiaoxie.servlet.FirstServlet</servlet-class>
</servlet>
或者是用注解 在类的开始加上如下:
@WebServlet("/FirstServlet")
在web.xml中还可以使用一下可选的配置参数
<init-param>  配置servlet初始化参数
<load-on-startup> 配置servlet的加载方式可选0,1,其中1表示启动Tomcat时自动加载
如上是已经配置好了一个servlet对应的类还需要进行<servlet-mapping>的配置
<servlet-mapping>
 <servlet-name>FirstServlet</servlet-name> 需要与配置的Servlet的名字相同
 <url-pattern>/FirstServlet</url-pattern> 配置Servlet的访问对应的url
</servlet-mapping>

服务器对端的响应被封装在一个HttpServletResponse对象,要对浏览器进行操作只需要操作HttpServletResponse对象就可以了
HttpServletResponse.getWiter()--->得到一个PrintWriter对象,接下来使用这个对象输出信息就可以了
注意PrintWriter对象只能写字符型的数据如果要写二进制的数据则需要使用HttpServletResponse.getOutputStream()

对于Java web开发中,对于常量尽量写在配置文件中,这样可以更好的适应需求的变化
初始化参数
在web.xml当中在配置servlet时可以在其中添加<init-param>配置初始化参数,并且在一个Servlet中可以配置0到多个
在配置完毕后 可以在servlet中使用方法getInitParameter(String param)来获得初始化参数的值
如果配置了名为param的参数,则返回参数值,否则返回null
方法getInitParameterNames()会返回所有的参数名称,返回的类型是Enumeration

注意 WEB-INF下的文件是不可以通过浏览器直接进行访问的但是注意它是可以通过程序跳转进行访问的

init-param是配置在<servlet>标签中的,只能由某一个servlet来读取,它不是一个全局的参数。
如果需要配置一个所有的servlet都可以访问得到的参数则需要使用上下文参数context-param,使用标签<context-param>来实现
获取context-param可以使用ServletContext对象来实现
getServletConfig().getServletContext()--->得到ServletContext
接下来可以通过getInitParameter()来获得指定参数名对应的参数值,也可以通过getInitParameterNames()来获得所有的参数名
初始化的参数和上下文参数只能是配置简单的字符串类型的参数
一般来说把参数配置写到xml文件或者是properties文件中,然后通过程序来读取这些文件

资源注射
在web.xml当中去做资源的配置,这个时候的配置不需要Servlet去主动去获得这些资源而是在Tomcat启动的时候去注射到servlet中

@Resource(name="xml中配置的资源名称")
private String message;
或都如下写法也可
private @Resource(name="xml中配置的资源名称") String message;

在web.xml中配置资源形式如下:
<env-entry>
   <env-entry-name>hello</env-entry-name>
   <env-entry-type>java.lang.String</env-entry-type>
   <env-entry-value>Hello,Welcome to the JavaEE.</env-entry-value>
  </env-entry>

  资源的注射工作原理是JNDI,如果在程序中不使用@Resource把指定的资源进行注射可获取资源的话可以通过程序来读取
  Context ctx = new InitialContext();  //实例化一个Context对象
  String message = (String)ctx.lookup("hello"); //查找hello资源

Web应用程序的任务是实现客户端浏览器与服务器之间的信息交互
浏览器提交信息--->servlet读取信息--->servlet做逻辑判断--->servlet生成相应的响应给到浏览器
信息交互分为两种GET、POST
GET:
主要是浏览器向服务器提交请求来查询相应的信息
HTML当中form提交数据,form中的method属性设为get时浏览器就是以get方式来提交表单数据的,form中的action属性则设置提交
到哪个url。
GET方式提交数据的时候会把表单的信息组成一个查询字符串(query string),各个表单的变量以&进行链接,然后以servlet路径
加上?再加上查询字符串的形式来获取服务器的内容。
GET方式提交表单时,所有被提交的数据都会显示在地址栏中,这些被提交的信息可能被浏览器记录在缓存中,因而对于敏感信息
不能使用GET方式进行提交,而且浏览器地址URL长度是有限制的,总长度是不可以超过255个字符的,过长的内容也是不适合使用
GET方式提交的
POST:
POST方式提交表单内容时,提交的信息不会显示在地址栏中,在地址栏中只会显示接受这个表单数据的Servlet路径,并且POST提交的数据
是没有长度的限制的,与GET不同的是POST提交的数据不会组织成一个QueryString因而调用方法getQueryString()会返回null

文件上传
上传文件也是一种常见的客户端与Web程序交互的操作,相对于FTP文件上传,web文件上传要慢一些,它是不需要额外的客户端的
上传文件也是使用的POST的方式,与表单的提交信息不同的是它在form的enctype属性中要指定multipart/form-data(二进制数据上传),如果
这里不设置的话则会使用默认的application/x-www-form-urlencoded,这个时候浏览器是使用ascii向服务器发送数据
上传文件要使用文件域<input type='file' />

上传文件中浏览器是以二进制的方式来发送数据,因而是不可以简单使用HttpServletRequest的getParameter()来获取文件域或文本域中的数据
必须要按HTTP协议所规定的格式来进行解析浏览器数据
解析二进制数据流有一些已写好的类库,比如商业类库SmartUpload,把解析的数据放在内存中速度比较快,但对于大文件的上传会可能产生内存
溢出
开源类库:Apache Commons FileUpload,在某些框架中也集成了它
带进度条上传:
进度条上的相关信息会先存入到session当中,客户端的浏览器通过Ajax技术再开一个独立的线程,从session中获取到上传进度信息,并作实时的
显示,Ajax可以在不刷新页面的情况下获得到服务器的数据,Session可以看成是服务器的内存
commons-fileupload 1.2版本中有一个上传监听器
监听器要实现ProgressListener接口
在Servlet中需要安装上相应的监听器

Servlet生命周期:
每个Servlet都有自己的生命周期,Servlet的生命周期由Web服务器来维护
CGI编程中,用户请求一次CGI程序则服务器就开辟一个进程来处理请求,处理完后即把这个进程销毁掉。这样做效率低下
Servlet中在服务器启动时(load-on-startup为1)或者是第一次请求Servlet时(load-on-startup为0)初始化一个Servlet对象,然后利用这个
对象去处理所有客户的请求,服务器在关闭时才会销毁这个Servlet对象,这样可以省掉开辟和销毁servlet的开销。
当有多个客户端进行并发请求Servlet的时候,服务器会启动多个线程分别去执行servlet的service()方法

init(ServletCofig conf)  加载Servlet时运行这个方法
  |
  |
service(ServletRequest req,ServletResponse res)  每次请求会运行这个方法
  |
  |
上面的方法判断访问的类型根据req的getMethod()返回的结果
判断执行doGet还是doPost。。。
  |
  |
 destory() 卸载Servlet时执行这个方法

在生命周期当中init(ServletConfig config) 和 destory()都只会执行一次 而service()会执行多次 因为请求是多次的。
对于Servlet的init(ServletConfig config)方法 HttpServlet提供了一个更简单的不带参数的方法init()来代替,ServletConfig可以通过
getServletConfig()来获得

JAVAEE 5.0后有两个注解会影响上面的生命周期:
@PostConstruct 和 @PreDestory
这两个注解被有来修改一个非静态的void方法,并且这个方法是不可以抛出异常声明的
方法的写法如下
@PostConstruct
public void someMethod(){
 ...
}
或者是
public @PreDestory void anotherMethod(){
 ...
}
@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且它只会被服务器调用一次的,它会在Servlet构造器之后并且在init()方法之前运行
@PreDestory修改的方法会在服务器卸载Servlet的时候运行,并且也只会被服务器调用一次,它会在desory()方法之后Servlet卸载完成之前执行
完整的生命周期则如下
服务器加载Servlet
 |
 |
Servlet构造函数运行
 |
 |
@PostConstruct修改的方法
 |
 |
init(ServletConfig conf)
 |
 |
service(req,res)
 |
 |
destory()方法
 |
 |
@PreDestory修饰的方法
 |
 |
服务器卸载Servlet完毕

注解是会影响到服务器的启动速度的,服务器在启动的时候会遍历所有WEB-INF/classes下的class文件以及WEB-INF/lib下的jar文件,以检查哪些类使用
了注解,对于不支持注解的服务器则无需这一步,如果在各序中没有注解则可以在web.xml的<web-app>中加上相应的属性如下:
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5" metadata-complete="true">
 ...
</web-app>

各个Servlet之间的跳转:
Servlet之前可以实现跳转 可以从一个Servlet处理跳转到另一个Servlet,这样就很容易使用得把一个任务按模块进行分开
一项任务拆分:
接收用户数据Servlet
进行业务操作Servlet
读取数据Servlet
处理结果显示Servlet
现在MVC框架都是使用了Servlet的跳转,MVC框架把程序分成了三个独立的模块
业务模块model,视图模块view,控制模块control
跳转分类:
转向(客户请我办一件事,我处理不了找相关的同事处理再告诉客户,客户不知道我处理不了)
Forward,它是通过RequestDispatcher对象的forward(req,res)来实现的
这里的RequestDispatcher可以初过request的getRequestDispatcher()方法来获得
如:
RequestDispatcher dispatcher = request.getRequestDispatcher("/servleturi");
dispatcher.forword(req,res);
注意:getRequestDispatcher()方法的参数必须要以"/"这个开始,这里的"/"表示应用程序的根目录,也就限定了这种转向只能是在本应用之内的转向
在使用forward形式进行Servlet的跳转的时候地址栏上会显示跳转前的servlet访问地址,因为这个跳转是在服务器端进行的客户端并不知道有这个跳转、
通常我们的用法是在一个servlet中把处理的结果通过request.setAttribute()放到request当中然后forward到jsp中去显示

在执行forward动作的时候不能有任何的输出到达客户端,否则会抛出异常IllegalStateException
在forward之前尽量不要使用out.println()对客户端输出结果

重定向(客户请我办一件事,我处理不了我直接告诉客户我处理不了并告诉他重新找哪位同事去处理,客户完全知道处理人是谁)
Redirect 它是利用服务器返回回来的状态码来实现的。客户端浏览器请求服务器的时候,服务器会返回一个状态码,服务器通过Response的setStatus(int status)
方法来设置状态码,如果状态码是301或者302,则浏览器会从新的网址重新请求资源
状态码:
1xx:信息状态码,表求请求已经被接受,正在处理
2xx:正确状态码,表示请求已被接受并处理,没有发生错误,比如:200表示一切正确
3xx:重定向状态码,这时客户端需要重新定向到一个新的资源,服务器响应会附带这个新的资源的地址
4xx:表示请求错误,401:权限问题,404:资源不存在,405:访问方式错误
5xx:服务器错误,500表示程序出现异常而中途停止

301与302的区别:
301表示永久重定向,302表示临时重定向
注意 重定向则不限于本应用可以重定向到其它的网站
重定向的方法:
//设置状态码为302
response.setStatus(HttpServletResonse.SC_MOVE_TEMPORARILY);
//指定重定向的地址
response.setHeader("Location","http://www.baidu.com");

HttpServletResponse把setStatus和setHeader方法封装成另一个方法sendRedirect(String location),这样只需要调用这个方法就可以实现重定向了

自动刷新
使用自动刷新不仅可以实现过一段时间后跳转到一个指定的页面,还可以实现按一段时间后刷新本页面,在Servlet中通Response的header属性来实现
response.setHeader("Refresh","1000; URL=http://localhost:8888/web/example.html");
注意这里的1000是毫秒

关于Servlet与线程安全问题:
线程安全简单的讲就是在多线程并发操作的时候不会出现问题。
Servlet只会有一个实例,多个客户端同时请求的是同一个Servlet,服务器会产生多条线程执行Servlet的代码,这样的话Servlet是有线程安全的隐患的

多线程的并发读写是会导致数据不同步的问题的,解决的办法是尽量不要使用公共的属性,把属性定义成为局部的变量
对于并发的读不写的话也是不会存在数据不同步的问题的,因而在Servlet中对于只读属性最好的定义为final

0 0
原创粉丝点击