1、Servlet:
Servlet是JavaWeb的3大组件之一,是把url请求转为后台处理的具体类,此类必须实现Servlet接口,一把实际使用时无须我们实现,我们直接使用JavaEE的HTTPServlet,其内部已实现Servlet接口,Servlet生命周期为init()创建,Service()服务,Destroy()销毁3个阶段,创建是在第一次请求访问时进行init(),创建完以后就不会再创建,会一直存在于tomcat中,init()方法主要是初始化Servlet的一些配置参数,如果想不想只在第一次访问时才创建servlet实例,而是在tomcat请求时就创建servlet,那么可以在web.xml中配置一下一下load-on-startup级别,数值越小越提前创建,从1开始,0被tomcat默认的所占,自己不要用。Servlet是一个单例的,整个生命周期只有一份。其后每次访问过来时调用的都是Service()方法为每个请求进行服务,当tomcat卸载或停止后,会触发Destroy()方法进行销毁前回调
Servlet能处理url请求,主要是通过web.xml中的路径和Servlet类的映射
<servlet> <servlet-name>abc</servlet-name> <servlet-class>对应的Servlet完整类名</servlet-class> </servlet> <servlet-mapping> <servlet-name>abc</servlet-name> <url-pattern>可以自己指定url路径,不重复就行</url-patter> </servlet-mapping>
由于Servlet是单例的,当有多个人同时访问时就会存在并发安全问题,并发的安全问题主要就是操作共享数据的问题,但是web程序加锁的话就会影响性能,所以这就要求不能在Servlet类中定义可写操作的成员数据(只读的共享数据没问题),只能使用方法内部的局部数据,因为方法调用时是各自独立的,方法内部的局部数据在每次访问时都是与线程相关的本地数据,线程结束,数据作用域结束,所以是线程安全的,基于此SpringMVC的Controller也就是在Service方法中做的文章。
Servlet初始化的时候进行配置文件参数初始化,这个对象为ServletConfig,其可以获取到初始化参数,ServletContext等信息。初始化参数配置也是在web.xml中进行配置:
<servlet> <servlet-name>abc</servlet-name> <servlet-class>对应的Servlet完整类名</servlet-class> <init-param> <param-name>参数名1</param-name> <param-value>参数值1</param-value> </init-param> <init-param> <param-name>参数名2</param-name> <param-value>参数值2</param-value> </init-param> </servlet>
获取Servlet初始化参数通过ServletConfig的getInitParameter(String 参数名) 来进行获取
Service(request,response)方法中主要用来处理请求响应,请求的参数可以通过request参数进行获取,响应通过response参数进行返回,原始的Servlet接口开发时不需要自己实现,在Servlet接口下有一个基本类GenericServlet类,GenericServlet类下有一个专门处理HTTP请求的HTTPServlet类,已有各个web容器厂商实现,开发时直接继承HttpServlet类,重写各种请求方式doGet(),doPost()等即可,Service()服务方法内部会调用重写后的doGet(),doPost()方法来进行请求响应处理,如果自己继承的类中没有重写doGet()或doPost(),但是请求时以get或post方式进行请求,那么默认会调用tomcat中的doGet或doPost方法,而默认的doGet或doPost中只会返回405的浏览器状态码,405表示此种请求方式不支持,所以doGet或doPost方式必须自己进行重写
servlet的url路径匹配规则:
如果url匹配只写个杠,如<url-pattern>/</url-pattern>,那么只匹配根目录,这种匹配优先级最低,是所有其他的路径匹配都没有匹配成功时才走这个匹配,tomcat中web.xml有配置此匹配为处理找不到路径时默认的servlet处理,404就是tomcat的默认servlet返回的,实际开发中不配置servlet的/匹配
servlet中有方法getServletContext() 可以获取ServletContext,ServletCOntext是一个单例的,tomcat启动时就会创建,一个项目只有一份,所以也叫application域,是所有域中作用范围最大的域,其作用域的值在所有servlet中都可以获取和传递,ServletContext本质上是一个大Map,可以存值和取值,
getAttribute(String name)和setAttribute(String name, Object object),ServletCOntext可以获取web.xml中公共的初始化参数,这样达到配置的参数在所有servlet中可以共享,而在servlet中配置的参数仅限于当前servlet中使用,配置是直接在web.xml中添加<context-param>节点,如下:
<context-param> <param-name>名</pram-name> <param-value>值</param-value> </context-param>
由于公共的配置参数只能通过ServletContext获取,所以在Servlet中先拿到ServletContext,代码如下:
ServletContext application = this.getServletContext(); String val= (String)application.getInitParameter(name) ;
ServletContext作用域的用途还有获取资源文件路径(从webroot下开始,即根目录下开始),甚至把资源路径下文件转为流,如下:
不过第三个方法获取所有路径,这种方式仅获取web-inf下lib文件夹,classes文件夹,但是内部不会进去访问,web-inf下的文件,如web.xml可以访问到,总之这个方法没啥卵用,了解即可
通过ClassLoader可以获取类路径classes下的资源,即classpath下的文件,其实也就是通过类加载器加载src下的配置文件之类的文件,类加载器既然可以加载类文件,那么加载其他类型文件也是一样的,方法操作过程如下:
ClassLoader多用于操作classes下的配置文件,其根如/a.txt是以classes为根目录,如果要操作项目根目录下的文件,多用ServletContext来操作
2、HTTPServletRequest和HTTPServletResponse
HTTPServletRequest是ServletRequest的子接口,HTTPServletResponse是ServletResponse子接口,这两个子接口是Servlet专门用于处理HTTP请求响应的,其内部的特定方法有:
2、Listener监听器
Listener也是JavaWeb的3大组件之一,主要是用来监听3大作用域的ServletContext,HttpSession,HttpServletRequest的创建销毁,赋值和删除值操作
监听器创建步骤如下:
如果想在tomcat启动时进行操作,可以在 ServletContext监听器初始化监听方法中进行,spring就是在这个监听器中完成配置文件加载,各个bean的初始化,监听器中用的多的也就是初始化监听,可以配置多个ServletContext监听器,但是监听器不等于application作用域,其只是监听application作用域,可以监听作用域的初始化时的进一步操作,比如获取ServletContext往里面添加一个Map以便自己存放数据等操作,在整个应用程序中ServletContext只有一份,ServletContext是tomcat创建的。属性值变化的监听需要实现xxxAttributeListner接口,不过属性值监听用的很少,了解即可
3、Filter过滤器
过滤器也是JavaWeb的3大组件之一,常用于请求访问前的拦截校验操作,过滤器编写需要实现一个Filter接口,并在web.xml中进行配置,可以配置多个过滤器,每个过滤器校验通过会放行到下一个过滤器。每个Filter都是单例的,只实例化一次。服务器启动时就会实例化,过滤器的拦截一般都是为整个网站服务的,所以urlPattern拦截的都是/*,很少配对每一个路径进行拦截的,拦截器会拦截所有请求,包括jsp,html,图片,css等,拦截器常用的拦截方式有4种,分别是拦截请求request,拦截转发forward,拦截包含include,拦截错误error,具体拦截哪种类型,还是所有类型都拦截,可以在web.xml中进行配置,默认不配置拦截的就是request,
Filter各个方法说明,doFilter是拦截方法,在此方法中可以做放行之前的预处理,放行后到达servlet后返回到doFilter方法,此时可以做返回给用户之前做一些回程处理:
过滤器的执行顺序,由配置文件中filter-mapping的顺序决定,定义在前面的先执行,后面的后执行。
4、在过滤器中经常要做处理的就是request和response,而传过来的request默认是各个web容器实现的组装,而request不能setparameter,只能getparameter,而又不能直接对各个web容器实现的request进行修改,因为各个容器实现方式不一样,不能限制客户只能用tomcat等web容器,所以这时需要实现javaee的HttpServletRequest接口,但是这个接口内部有30多个方法,完全自己去写也不现实,而且完全写就会覆盖各个容器的实现,而javaee早就预料到肯定会有对request进行重新操作的情况,这时其内部提供了一个HttpServletRequestWrapper包装类,其内部已实现HttpServletRequest接口,而这个接口tomcat也实现了,所以是通用的,只要在调用之前让tomcat先走一遍,就可以让内部的实现完成各个厂商的实现,然后自己把需要操作的方法拿出来重写,重写完以后往下传递调包后的request对象就可以实现get请求等情况的重新处理,同理的还有HttpServletResponseWrapper包装对象。如下:
同理的还有HttpServletResponseWrapper类
这种对request进行调包的方式在struts中就有使用,struts的request功能比javaee提供的原始request功能强,就是因为其包装了一层,并传递了调包后的request,struts的request甚至可以在页面重定向时传递跳转前一个页面的参数,原理就是上面所述,没什么特别的
JSP的3大指令:page指令,include指令,taglib指令
JSP的9大内置对象,可以直接在<% %>中进行书写的对象:
JSP的动作标签,即以<jsp:开头的服务端标签,用的不多,是request和response中跳转包含的页面上使用的简写形式,常用的有跳转和包含,其中在jsp中include有两种形式,分别是Include指令:<%@ include file=""%>和include动作:<jsp:include page="" flush="true"/> ,两者的区别是include指令元素(<%@ include file=""%>)所指定的页面的实际内容(也就是代码段)加入到引入它的jsp页面中,合成一个文件后被jsp容器将它转化成servlet。可以看到这时会产生一个临时class文件和一个servlet源文件。而动作元素(<jsp:include page=""/>)是在请求处理阶段引入的,会被JSP容器生成两个临时class文件和两个servlet原文件。而引入的只是servlet的输出结果,即JspWriter对象的输出结果,而不是jsp的源代码。总的来说两种include 两种用法的区别,主要有两个方面的不同:
一、执行时间上:
<%@ include file=”relativeURI”%> 是在翻译阶段执行
<jsp:include page=”relativeURI” flush=”true” /> 在请求处理阶段执行。
二、二:引入内容的不同:
<%@ include file=”relativeURI”%> 引入静态文本(html,jsp),在JSP页面被转化成servlet之前和它融和到一起。
<jsp:include page=”relativeURI” flush=”true” /> 引入执行页面或servlet所生成的应答文本。
说白了就是<%@ include file=”relativeURI”%>是源文件的包含,而<jsp:include只是方法调用而已,编译生成的servlet中仅出现dispatcher.include(‘b.jsp’)这个方法调用,页面源文件并未合并,只是调用另一个页面的输出结果
EL表达式,JSP中的表达式语音,语法格式是${},大括号中写4大域中的名称,会先从pageContext域查找,如果这一级没查到就到request域查找,最终查找到application域,都没有查找到输出空串,不会报错。EL表达式主要是操作输出域中对象,所以如果对象没有被加到域中,那么是遍历不出来的,这也是容易疏忽的地方,如:
如果不想全局域查找,而是从指定域中查找,那么可以通过域点出属性名,注意不要漏了Scope,如requestScope,不能写错request,如下:
EL表达式设计出来就是用来进行输出的,不能设置值,要设置值可以通过JSTL动态标签库进行,jsp2.0后不允许使用jsp脚本语言<%= %>,而改用EL表达式和JSTL动态标签库。
EL表达式输出时支持导航语音,通过一个对象点出其下属性值,注意不能加get,直接通过属性名就行,如下:
EL表达式运算:
EL表达式内置的11个对象:
这些EL对象,其实很多都是后台方法的简化版,如获取参数,详细写法是request.getParameter("abc"),简写成EL表达式的${param.abc}。由于这些内置对象除了pageContext不是Map对象,其他都是Map对象,所以取值时可以通过点来获取属性值,也可以通过中括号[]来获取,参数用引号引起来,如 ${param['abc']}
EL表达式除了可以使用上面的内置对象外,还可以使用函数库,由于函数库是JSTL提供的,所以使用前得添加jstl.jar,并在页面导入此jar中提供的标签库jstl,如:
EL使用函数库例子:
除了使用jstl提供的函数库外,还可以自定义函数库,不过EL函数库没多大用处,普通的字符处理,在页面上JS就可以搞定,没必要借助函数库
JSTL这个jar包中还提供了JSTL标签库,常用的标签库有core,fmt(格式化)这两种标签,其他的用的不多
JSTL是第三方jar包,需要导包,而且其依赖EL表达式,JSTL标签库是在web容器中执行,其执行完输出结果后才会和html标签进行合并渲染成最终HTML元素展示到浏览器,所以JSTL标签库和html标签嵌套使用不会相互影响,因为两种标签执行时机不一样,一个是服务端,一个是客户端
fmt标签,主要用于格式化,常用的有两个,日期和数字