JavaWeb开发中有几个重要的东西,俗称javaWeb的三大组件:Servlet、Filter、和Listener。其中Servlet是javaWeb中最重要的一个组件。下面一起来在学一次这个组件。
首先Servlet是什么?
Servlet 是一个接口,和他对应的有两个常用的类,GenericServlet、HttpServlet。
Servlet 的使用,Servlet 由Tomact 等服务器创建并在有人请求这个Servlet的时候调用,我们只是完成了Servlet中变化的部分。
Servlet的五个方法:
普通方法:
getServletConfig();
获取Servlet 的配置信息,提供我们获取Servlet的信息,可以在Servlet的init()方法执行后给他赋值返回。
getServletInfo();
获取Servlet的信息,,服务器不会调用,提供我们自己调用。
生命周期方法:
init();
在Servlet对象创建后马上执行,并只执行一次。
service();
多次执行的Servlet请求方法,在每次调用Servlet都会去执行这个方法。
destory();
在Servlet被销毁前调用,并且只会调用一次。注意:这不是Servlet用来自我销毁的方法,只是在销毁前执行,理论上这里用来释放一些非内存资源。
如何让浏览器访问Servlet?
1.给Servlet指定一个Servlet路径
2.浏览器访问Servlet路径,从而调用Servlet方法。
设置:
在Web.xml中对Servlet进行配置。
<servlet>
<servlet-name>XXX</servlet-name>
<servlet-class>这里是Servlet类的</servlet-calss>
</servlet>
<servlet-mapping>
<servlet-name>XXX</servlet-name>
<servlet-pattern</AServlet></url-pattern>
</servlet-mapping>
一个浏览器的请求:Http:localhost:8080/test/AServlet
请求中访问一个AServlet的路径,然后在Web.xml中找到对应的映射mapping,然后找这个映射的名字的类,对应到了这个名字的类,这样就找到了这个类。这个配置关系是这样规定的。
我们创建一个Servlet类,模拟一个请求,然后访问。一个Servlet总共被执行一次init方法,但是执行多次service()方法,由此我们知道,Servlet的对象是一个单例模式的对象。
Servlet的特性:
三个生命周期方法,init(),service(),和destory(), service()会执行多次,其他两个只执行一次。一个Servlet只会创建要给对象,一个项目存储在多个Servlet,他是线程不安全的,因此也是高效率的。Servlet程序由程序员来写,但是由服务器(如Tomact)来创建对象和调用。
Servlet类:
首先了解一下ServletConfig
之前写了Web.xml,在这个xml中写了一个个的Servlet的配置,如上,这个代码也会在程序执行时加载到内存中,最后会解析成一个个对应的ServletConfig,所以我们可以在后期从ServletConfig中获取到一些信息。
看javaEE文档,找到GenericServlet对应的类,我们看方法:
String getServletName(),获取<servlet-name></servlet-name>中的名称。
这里没有提供获取ServletClass类的方法,这样是不安全的。
ServletContext getServletContext():获取Sservlet 上下文对象。我们在这里使用的都是一些接口,tomact会去对接口实现,我们在使用中直接调用即可。
String getInitParammeter(String name);通过名称获取制定初始化参数的值
Enumeration getInitParameterNames();获取所有初始化参数的名称
这些方法获取的参数就是Web.xml中一个个Servlet的配置信息的配置。
ServletConfig:
<servlet>
<servlet-name>XXX</servlet-name>
<servlet-class>这里是Servlet类的</servlet-calss>
<init-param>
<param-name>p1</param-name>
<param-value>v1</param-value>
</init-param>
<init-param>
<param-name>p2</param-name>
<param-value>v2</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>XXX</servlet-name>
<servlet-pattern</AServlet></url-pattern>
</servlet-mapping>
配置好后我们就可以在初始化方法init()之后去获取这些信息了。init()方法提供了一个
ServletConfig对象的参数)
Servlet 中为了直接使用SerlvetConfig 提供了一个方法:getServletConfig()方法。因此,如果是集成了这个类就可以直接使用这些参数。未了防止我们在子类中遗忘从写了Servlet的init()方法,我们可以在一个实现类中写一个自己的init方法,在Servlet的init()方法调用,然后提供给子类去重写覆盖。这样保证了Servlet的init()方法执行,给ServletConfit赋值,提供子类使用ServletConfig 对象。
GenericServlet类:
GenericServlet 这个类直接就是这样处理的,我们可以重写GenericServlet 的无参数init()方法初始化一些东西。因此,GenericServlet 类也就只有一个Service()方法是必须由其子类处理实现的。
HttpServlet:
在javax.servlet.http.**包下的类
请求对象方法:
doGet()、doPust(); servce();
HttpServlet 下有两哥service()方法,一个和Servlet去service()方法不一样,参数是和HttpServlet相关的。
HttpServlet继承了GenergicServlet ,有一个方法service(ServletRequest request , ServletResponerespone);在这个方法中强转参数为HttpServletRqequest和HttpServletResponse类型,然后调用本类的service(HttpServletRequest request ,HttpServletRespone respone);这个http相关的service()方法又可以通过request参数得到当前的请求方式:GET或者POST根据请求方式在调用doGet()或者doPost()方法。所以在最后我们只需要重写doGet()或者doPost()方法即可。如果我们没有重写doGet()或者doPost()方法,请求就返回一个405异常,表示不支持该请求。
Servlet的细节:
Servlet是线程不安全的,对于我们初学者,不要在Servlet中创建成员变量这样可以避免这个问题。后期我们可以创建无状态成员这样可以完成,最后我们可以创建只读的变量也可以避免这个问题。
<url-pattern>在设置的时候可以配置多个,也就是说Servlet可以配置多个访问路径。(早期的时候多个路径充当其他的作用)我们也可以设置通配符“*”,可以匹配多个路径如:
<url-pattern>/servlet/*</url-pattern> //匹配/servlet/*
<url-pattern>*.do</url-pattern> //匹配扩展名<url-pattern>/*</url-pattern> //匹配所有的url
上述几个匹配,直接没有“*”匹配的url优先级最高,匹配的越多的优先级越低,注意:通配符“*”不能再路径中间
web.xml的“继承关系”:
在tomact中的配置文件中conf下有一个web.xml和我们每一个项目下的web.xml相同,这个tomact下的web.xml中的内容就相当于写在了每个项目的web.xml中,就像是我们Java中的继承关系一样。我们可以在tomact中的web.xml中查看,有一个default的Servlet的配置,他的优先级最低,
如果一个请求没有任何的Servlet去相应请求,这个默认的Servlet就会相应,显示404错误。
我们也可以在tomact的web.xml中找到一个名为“jsp”的url,这个url用来相应jsp页面的相应,也就是说我们每次在地址栏访问一个jsp的时候会由这个url来处理。
另一个配置:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
上述在tomact的web.xml中配置表示我们设置session的过期时间是30分钟。
还有一些其他的如:
<mime-maping>
<extension>gif></extension>
<mime-type>image/gif</mime-type>
</mime-maping>
上述用来匹配gif图片,还有其他的url用来匹配我们常见的一些文件。
Servlet中的反射:
我们现在知道了在浏览器中请求一个地址会带有一个Servlet的url-pattern,通过这个url-patternt我们可以获取一个Servlet-name从而拿到Servlet-class的一个字符串有了这个字符串我们就可以通过反射创建这个Servlet类的对象了,但是我们必须保证这个Servlet有一个无参的构造方法,防止我们在写了一个有参数的构造后忘了无参数的构造方法。有了类的对象我们就可以获取Method 方法,然后去调用其他的方法,执行Servlet。这就是Servlet的创建和调用过程。
ServletContext上下文对象:
一个项目只有一个ServletContext对象
可以在多个Servlet中获取同一个ServletContext对象,来给其他Servlet传递数据。
ServletContext 在服务器启动的时候创建,服务器关闭的时候销毁。ServletContext的作用就是砸iweb应用的动态资源之间共享数据。
获取ServletContext :
1.在Servlet接口类的init(ServletConfig config)方法中通过config.getServletContext()方法来获取这个对象。
2.在GenericServlet 类中有一个getServletContext()方法,所以可以直接来使用this.getServletContext()回去这个对象。
3.HttpServlet 类或者子类中this.getServletContext();方法
4.HttpSession 中有一个获取ServletContext的方法。
上述所有的方式获取的都是同一个ServletContext对象。
ServletContext是javaWeb四大域对象之一
域对象的功能:在Servlet中传递数据,具有存数据的功能和去数据的功能(域对象中其实有一个Map对象)。
ServletContext操作数据的方法:
setAttribute("xxx","yyyy");要是多次调用这个方法并且“xxx”第一个参数一样,那么会覆盖上一次的值,这一特性和Map相同。
getAttribute("xxx","yyyy");用来获取ServletContext中的数据,在获取之前要先去存储才行,String value = servletContext.getAttribute("xxx");获取一个名为“xxx”的属性。
removeAttribute("xxxx");移除名为“xxxx”的属性
getAttributeNames(); //获取所有的域属性的名称,结果是一个Enumeration对象。
获取应用的初始化参数:(Servlet中也可以获取初始化参数,但是它是局部的,只能在自己的Servlet准备使用)
ServletContext 可以配置公共的初始化参数,为所有的Servlet而用。
设置:在web.xml中的根元素下和Servlet同级(web-app)下设置一个
<context-param>name</context-param>
<context-param>value</context-param>
然后在Servlet中就可以通过ServletContext 这个对象获取这些公共的初始化参数。
ServletContext app = this.getServletContext();
String value = app.getInitParameter("name");//获取到设置的值
使用ServletContext获取资源真实路径:
项目中获取一个路径:String path = this.getServletContext().getRealPath("");//获取一个带有盘符的真实路径
如果我们要获取一个真实的路径是:String path = this.getServletContext().getRealPath("/index.jsp");
获取资源流:InptuStream input = this.getServletContext().getResourceAsStream("/index.jsp");
获取所有资源的路径:this.getServletContext().getResourcePaths("/WEB-INF");//获取WEB-INF下的所有目录(这个方法必须以“/”开头)
获取类路径下的资源:
获取类路径下的资源,类路径就是一个JavaWeb项目而言就是WEB-INFclasses和WEB-INF/lib下的jar包(src下的文件在项目运行发布后都会复制在WEB-INF/class下)
流程:
获取一个ClassLoader 对象,然后调用其getResourceAsStream()。获取一个Stream
如:ClassLoader cl = this.getClass.getClassLoader();
InputStream in = cl.getResourceAsStream("xx.txt");//获取src目录下一个名字为“xx.txt”的文件(使用Connoms-io.jar这个包可以方便的操作iol流)
String ss = IOUtils.toString(in);//调用commons-io.jar包下的方法转化一个IntputStram 转换成字符串。
注意:要是文件放在某个包下,我们要在上面的获取输入流的方法中添加上报名代表的路径,把包名的“.”转换为“/”.
另外的一个方式:
Class cc = getClass();//获取相对.classes文件路径下的文件,包路径下。
InputStream in = cc.getResourceAsStream("xx.txt");//使用Class方式获取包下的文件相对于.class文件下
文件放在src下使用Class方式获取:
Class c = getClass();//获取相对.classes文件路径下的文件,包路径下。
InputStream in = c.getResourceAsStream("/xx.txt");//添加“/”
实例:获取index.jsp文件:
Class c = getClass();//获取相对.classes文件路径下的文件,包路径下。
InputStream in = c.getResourceAsStream("/xx.txt");// InputStream in = c.getResourceAsStream("/../../index.jsp");//在.class路径下,往回退两层下