JSP、Servlet学习笔记
目录JSP:4种基本语法3个编译指令7个动作指令9个内置对象Servlet:Servlet自定义标签FilterJSP(JSP 2.3 )JSP的本质是Servlet,每一个JSP页面就是一个Servlet实例。当用户向指定Servlet发送请求时,Servlet利用输出流动态生成HTML页面,包括每一个静态的HTML标签和所有在HTML页面中出现的内容。JSP生成的Servlet存放在Tomca
目录
JSP:
Servlet:
JSP(JSP 2.3 )
- JSP的本质是Servlet,每一个JSP页面就是一个Servlet实例。
- 当用户向指定Servlet发送请求时,Servlet利用输出流动态生成HTML页面,包括每一个静态的HTML标签和所有在HTML页面中出现的内容。
- JSP生成的Servlet存放在Tomcat的work路径对应的Web应用下。
- JSP页面由系统编译成Servlet,Servlet再负责响应用户请求。web应用中的每个JSP页面都会由Servlet容器生成对应的Servlet。
- 每个Servlet在容器中只有一个实例。
JSP页面内容由两部分组成:
- 静态部分:标准的HTML标签、静态的页面内容,这些内容与静态HTML页面相同。
- 动态部分:受Java程序控制的内容,这些内容由Java脚本动态生成。
JSP原理的结论:
- JSP文件必须在JSP服务器内运行。
- JSP文件必须生成Servlet才能执行。
- 每个JSP页面的第一个访问者速度很慢,因为必须等待JSP编译成Servlet。
- JSP页面的访问者无须安装任何客户端,甚至不需要可以运行Java的运行环境,因为JSP页面输送到客户端的是标准HTML页面。
1. 4种基本语法
<%-- 注释内容 --%>
JSP注释不会输出到客户端
1.2 JSP声明
<%! 声明部分 %>
JSP的声明部分将转换成对应的Servlet的成员变量或成员方法。
JSP声明定义的变量和方法可以用private、public、static等修饰,但不能使用abstract修饰,因为抽象方法将导致JSP对应Servlet变成抽象类,导致无法实例化。
1.3 输出JSP表达式
<%=表达式%>
- 输出表达式后不能有分号;
1.4 JSP脚本
<% %>
JSP脚本将转换成Servlet里**_jspService方法**的可执行性代码,所以不能定义方法。
在JSP脚本中声明的变量是局部变量,不能使用private、public、static修饰。
- JSP页面里的所有静态内容都将由 _jspService 方法里的输出语句输出。
2. 3个编译指令
- page:针对当前页面的指令
- include:指定包含另一个页面
- taglib:定义和访问自定义标签
2.1 page指令
page指令各属性意义:
- language=“Java”:JSP页面脚本语言
- extends="":编译生成的Java类继承的父类,或实现的接口
- import="":导包
- session=“true”:设定JSP页面是否需要HTTP Session
- buffer=“none|8KB|size Kb”:指定输出缓冲区大小。
- autoFlush=“true”:输出缓冲区即将溢出时,是否需要强制输出缓冲区内容。
- info="":设置该JSP程序的信息,或说明。在JSP页面可直接调用getServletInfo()方法获取该值。
- errorPage=“URL”:指定错误处理页面。
- isErrorPage=“true”:设置本JSP页面是否为错误处理程序。如果true,则无须定义errorPage属性。
- contextType=“text/html; charset=utf-8”:设定生成网页的文件格式和编码字符集。默认为text/html; ISO-8859-1。
- pageEncoding=“ISO-8859-1”:指定生成网页的 编码字符集。
2.2 include指令
<%@include file=" "%>
可包含静态或动态JSP页面,页面会在编译时被完全包含。若频繁改变,则用jsp:include动作指令。
3. 7个动作指令
- jsp:forward:执行页面转向,将请求的处理转发到下一个页面。
- jsp:param:传递参数,必须与其他支持参数的标签一起使用
- jsp:include:动态引入一个JSP页面
- jsp:plugin:下载JavaBean或Applet到客户端
- jsp:useBean:创建一个JavaBean实例
- jsp:setProperty:设置JavaBean实例属性值
- jsp:getProperty:输出JavaBean实例属性值
3.1 forward
<jsp:forward page=" ">
<jsp:param name="" value=""/>
</jsp:forward>
- 使用HttpServletRequest的实例request获取值 :request.getParameter(“age”)
- 执行forward指令时,请求地址不变,请求参数不会丢失(并没有重新发送请求,只是跳转新页面生成响应)
- forward使用_jspx_page_context的forward()方法引入目标页面
3.2 include
<jsp:include page="" flush="true"/> // flush 指定输出缓存是否转移到被导入文件
- 动态的include指令,不会导入编译指令,只会插入页面的body内容
- 动态导入只是使用一个include方法来插入目标页面内容,而不是将目标页面完全融入本页面。
- include使用JspRuntimeLibrary的include()方法引入目标页面
静态动态导入三点区别:
- 1.静态完全融入页面,融合成一个Servlet,动态使用include方法引入被导入页面的内容
- 2.静态导入时,被导入页面编译指令有用,动态导入时被导入页面编译指令失效。只是插入被导入页面body内容。
- 3.动态可增加额外参数<jsp:param name="" value="" />
forward / include 区别:
- 被forward的页面将完全代替原有页面
- 被include的页面插入原有页面
3.3 useBean / setProperty /getProperty
与JavaBean相关:
- useBean用于在JSP页面初始化一个Java实例
- setProperty用于为JavaBean实例的属性设值
- getProperty用于输出JavaBean实例的属性
useBean语法:
<jsp:useBean id="" class="" scope=""/>
scope指定JavaBean实例的作用范围,有4个值:
- page:仅在该页面有效
- request:在本次请求有效
- session:在本次session有效
- application:在本应用内一直有效
3.4 plugin
主要用于下载服务器端的JavaBean或Applet到客户端执行,因为程序再客户端执行,所以客户端必须安装虚拟机。
3.5 param
param指令用于设置参数值,且不能单独使用。可以与以下三个指令结合使用:
- jsp:include
- jsp:forward
- jsp:plugin
4. 9个内置对象
- application:代表JSP所属的Web应用本身,可用于JSP页面,或在Servlet之间交换信息。常用setAttribute/getInitParameter
- config:代表JSP的配置信息。常用getInitParameter/getInitParameternames()。JSP通常无须配置,更多地在Servlet中使用。
- exceptoin:代表其他页面中的异常和错误。常用getMessage/printStackTrace。
- out:代表JSP页面的输出流,用于输出内容,形成HTML页面。
- page:代表该页面本身,没什么用,也就是Servlet中的this。
- pageContext:代表该JSP上下文,使用该对象可以访问页面中的共享数据。常用getServletContext/getServletConfig。
- request:该对象封装了一次客户端的参数的请求。常用getParameter/getParameterValues/setAttribute/getAttribute/setCharacterEncoding。
- response:代表服务器对客户端的响应。通常使用out输出,除非需生成非字符响应。常用于重定向。常用getOutputStream/sendRedirect。
- session:代表一次会话,客户端浏览器与站点连接时,会话开始,客户端关闭浏览器时结束会话。常用getAttribute/setAttribute。
JSP内置对象的实质:它们要么是_jspService()方法的形参,要么是_jspService()方法的局部变量,所以可以直接在JSP脚本中调用。
JSP脚本对应Servlet中的_jspService()方法部分。因此只能在JSP脚本、JSP输出表达式中使用内置对象, 不能在JSP声明中使用 !
4.1 application
Web服务器对每次客户端的请求需要完成:
-
- 启动单独线程
-
- 使用I/O流读取用户请求的二进制流数据
-
- 从请求数据中解析参数
-
- 处理用户请求
-
- 生成响应数据
-
- 使用I/O流向客户端发送请求数据
Web服务器会调用Servlet的_jspService()方法完成第3、4、5步,编写的JSP页面里的静态内容、JSP脚本都会转换成_jspService()方法的执行代码。这些执行代码负责完成解析参数、处理请求、生成响应等业务功能。而Web服务器负责完成多线程、网络通信等底层功能。
application通常有两个作用:
- 在整个Web应用的多个JSP、Servlet之间共享数据。
- 访问Web应用的配置参数。
application常用方法:
- getAttribute(String attrName)
- setAttribute(String attName, String attValue)
- getInitParameter(String paramName)
a. 在JSP、Servlet共享数据
application.setAttribute("attName", attValue); //将attValue放入application范围
application.getAttribute("attName"); //获取app范围里的值
application不仅可用于两个JSP页面之间共享数据,还可用于Servlet和JSP之间共享数据:
ServletContext sc = getServletConfig().getServletContext(); //Servlet没有内置对象application,需通过ServletContext实例获取值
sc.getAttribute("attName");
由于application代表整个Web应用,所以通常只应该把Web应用的状态数据放入application里。
b. 获得Web应用配置参数
String driver = application.getInitParameter("driver"); //从web.xml配置文件获得配置参数
在web.xml文件中配置参数:
<context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>
4.2 config
通常在Servlet中使用,Servlet需要在web.xml文件中进行配置并指定参数。
config.getServletName() //输出:jsp。因为所有的JSP页面都有相同的名字
也可以在web.xml中配置JSP,可以为JSP页面指定配置信息,并可为JSP页面设置另外一个URL
config对象时ServletConfig的实例,该接口用于获取配置参数的方法时 getInitParameter(String paramName):
<%=config.getInitParameter("name")%>
JSP当成Servlet配置,为Servlet配置参数使用inti-param元素,该元素可接受param-name和param-value两个子元素。
<servlet>
<servlet-name>config</servlet-name> //指定Servlet名字
<jsp-file>/***.jsp</jsp-file> //指定将哪个JSP配置成Servlet
<init-param>
<param-name>
<param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>config //指定将config配置到/config路径
<url-pattern>/config
</servlet-mapping>
4.3 exception
exception对象是Throwable的实例,代表JSP脚本中产生的错误和异常,是JSP页面异常机制的一部分。
在JSP脚本中无须处理异常,即使该异常是checked异常。JSP脚本包含的所有可能出现的异常都可交给错误处理页面。
JSP脚本和静态HTML部分都将转换为_jspService()方法里的执行性代码,JSP脚本无须处理异常的原因:
这些脚本已经处于try中,一旦try块捕捉到JSP脚本的异常,并且_jspx_page_context不为null,就会由该对象来处理异常。
_jspx_page_context对异常的处理:
如果该页面的page指令指定了errorPage属性,则将指令forward到errorPage属性指定的页面,否则使用系统页面就来输出异常信息。
JSP声明部分依然需要处理checked异常,JSP的异常处理机制对JSP声明不起作用。
<%@ page contextType="text/html; charset=utf-8" language="java" errorPage="error.jsp" %> //指定异常处理页面为error.jsp
error.jsp:
<%@ page contextType="text/html; charset-utf-8" language="java" isErrorPage="true" %> //指定为异常处理页面
异常类型:<%=exception.getClass() %>
异常信息:<%=exception.getMessage() %>
当JSP页面page指令的isErrorPage为true时,该页面才会提供exception内置对象。
在error.jsp页面生成的Servlet类的_jspService()方法中:
PageContext pageContext = null;
HttpSession session = null;
Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request); //初始化exception对象
if(exception != null){
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
4.4 out
out代表一个页面输出流,通常用于在页面上输出变量值及常量。
一般在使用输出表达式的地方,都可以使用out对象来达到同样效果。
4.5 pageContext
pageContext代表页面上下文,主要用于访问JSP之间的共享数据。
使用pageContext可以访问page、request、session、application范围的变量。
-
getAttribute(String name)
-
getAttribute(String name, int scope)
- PageContext.PAGE_SCOPE
- PageContext.REQUEST_SCOPE
- PageContext.SESSION_SCOPE
- PageContext.APPLICATION_SCOPE
-
setAttribue(String name, String value)
-
setAttribute(String name, String value, int scope)
pageContext.setAttribute("page", "hello"); //默认在page范围 pageContext.setAttribute("request2", "hello", pageContext.REQUEST_SCOPE); requestsetAttribute("request2", "hello"); //两种方式相同
pageContext还可用于获取其他内置对象,pageContext对象包含如下方法:
- ServletRequest getRequest()
- ServletResponse getResponse()
- ServletConfig getServletConfig()
- ServletContext getServletContext()
- HttpSession getSession()
4.6 request
request对象时获取请求参数的重要途径
request也可代表本次请求范围,所以还可用于操作request范围的属性
a. 获取请求头/请求参数
JSP和Servlet通过request获取请求参数,request是HttpServletRequest接口的实例,提供了如下几个方法:
- String getParameter(String paramName):获取paramName请求参数的值
- Map getParameterMap():获取所有请求参数名和参数值所组成的Map对象
- Enumeration getParameterNames():获取所有请求参数名所组成的Enumeration对象
- String[] getParameterValues(String name):paramName请求参数的值,当该请求参数有多个值时,该方法将返回多个值所组成的数组
HttpServletRequest提供了如下方法来访问请求头:
- String getHeader(String name):根据指定请求头的值
- java.util.Enumeration getHeaderNames():获取所有请求头的名称
- java.util.Enumeration getHeaders(String name):获取指定请求头的多个值
- int getIntHeader(String name):获取指定请求头的值,并将该值转为整数值
请求头通常由浏览器自动添加,而请求参数则通常需要开发人员控制添加,让客户端发送请求参数通常分两种:
- GET:直接在浏览器地址栏输入访问地址所发送的请求或提交表单发送请求时,该表单对应的form元素没有设置method属性,或设置method属性为get。GET方式的请求会将请求参数的名和值转换为字符串,并附加在原URL之后。GET请求传送的数据量较小,一般不能大于2KB。
- url?param1=value1¶m2=value2&…
- POST:通常使用提交表单的方式来发送。且需设置form的method为post。POST请求传输的数据量总比GET大。而且POST方式发送的请求参数以及对应的值放在HTML HEADER中传输,在地址栏看不到,安全性相对较高。
并不是所有表单都会生成请求参数,而是有name属性的表单域才生成请求参数:
- 每个有name属性的表单域对应一个请求参数
- 如果有多个表单域有相同的name属性,则多个表单域只生成一个请求参数,只是该参数有多个值
- 表单域的name属性指定请求参数名,value指定请求参数值
- 如果某个表单域设置了disabled="disabled"属性,则该表单域不再生成请求参数
获取请求头:
Enumeration<String> headerNames = request.getHeaderNames(); //获取所有请求头的名称
while(headerNames.hasMoreElements()){
String headerName = headerNmaes.nextElement();
out.println(headerName + " " + request.getHeader(headerName)); //获取每个请求及其对应的值
}
request.setCharacterEncoding("UTF-8"); //设置request的解码方式
String name = request.getParameter("name"); //依次获取表单域的值
String national = request.getParameter("country");
String[] color = request.getParameterValues("color");
String national = request.getParameter("country");
GET方式的请求值里包含了非西欧字符:
String rawQueryStr = request.getQueryString(); //获取请求里包含的查询字符串
String queryStr = java.net.URLDecoder.decode(rawQueryStr ,"UTF-8"); //使用URLDecoder解码字符串
String[] paramPairs = queryStr.split("&"); //以&符号分解查询字符串
for(String paramPair : paramPairs){
String[] nameValue = paramPair.split("="); //以=来分解请求参数名和值
}
还可以在获取请求参数值之后对请求参数重新编码:
String rawName = request.getParameter("name");
byte[] rawBytes = rawName.getBytes("ISO-8859-1");
String name = new String(rawBytes, "UTF-8");
b. 操作request范围的属性
HttpServletRequest包含两个方法:
- setAttribute(String attName, Object attValue)
- Object getAttribute(String attName)
forward用户请求时,请求参数和request范围的属性都不会丢失。
c. 执行forward或include
request代替JSP所提供的forward和include动作指令。
HttpServletRequest类提供了一个getRequestDispatcher(String path)方法,其中path就是希望forward或者include的目标路径,该方法返回RequestDispatcher,该对象提供了:
- forward(ServletRequest, ServletResponse response)
- include(ServletRequest, ServletResponse response)
如下代码可将a.jsp页面include到页面中:
getRequestDispatcher("/a.jsp").include(request, response);
getRequestDispatcher("/a.jsp").forward(request, response);
d. 访问Cookie
访问客户端Cookie使用request对象,它提供了getCookies()方法,返回客户端上所有Cookie组成的数组。
访问Cookie的JSP页面代码:
Cookie[] cookies = request.getCookies(); //获取本站在客户端上保留的所有Cookie
for(Cookie c : cookies){
if(c.getName().equals("username"))
out.println(c.getValue());
}
4.7 response
代表服务器对客户端的响应,大部分时候无须使用response来响应客户端请求,使用out来响应,代表页面输出流。
但out是Writer的子类JspWriter的实例,Writer是字符流,无法输出非字符内容,如图片、PDF文档等。
a. response响应生成非字符响应
img.jsp:
<%@ page contentType="image/png" language="java"%> //通过contentType属性指定响应数据是图片
...
ImageIO.write(image, "png", response.getOutputStream()); //将图像输出到页面的响应
也可以在其他页面使用 显示这个图片页面。
使用这种临时生成图片的方式可以非常容易地实现网页上的图形验证码功能。
b. 重定向
重定向会丢失所有的请求参数和request范围的属性,因此重定向将生成第二次请求,与前一次请求不在同一个request范围内,所以发送一次请求的请求参数和request范围的属性全部丢失。
HttpServletResponse 提供了一个 sendRedirect(String path)方法,用于重定向到path资源,即重新向path资源发送请求。
response.sendRedirect("redirect-result.jsp");
地址栏改为重定向的目标URL,相当于在浏览器地址栏里输入新的URL后按回车键。
c. 增加Cookie
Cookie通常用于网站记录客户的某些信息,比如客户的用户名或喜好。在下次登录时,网站可以获取到客户的相关信息,根据这些信息,网站可以对客户提供更友好的服务。
Cookie与session不同之处:session会随着浏览器的关闭而失效,但Cookie会一直存放在客户端上直到超出Cookie生存期限。
使用Cookie,客户端浏览器必须支持Cookie才行,客户端浏览器完全可以设置禁用Cookie。
response对象提供了:
- void addCookie(Cookie cookie)
增加Cookie。在增加前,必须创建Cookie对象:
String name = request.getParameter("name"); //获取请求参数
Cookie c = new Cookie("username", name); //以获取到的请求参数为值,创建一个Cookie对象
c.setMaxAge(24 * 3600); //设置生存期限
response.addCookie(c); //向客户端增加Cookie对象
如果浏览器没用阻止Cookie,在地址栏输入 http://localhost:8888/jspObject/addCookie.jsp?name=cui ,网站就会向客户端机器写入一个名为username的Cookie。
使用Cookie对象必须设置生存期限,否则Cookie将会随浏览器的关闭而自动消失。
如果Cookie中出现中文内容,需要用java.net.URLEncoder先对中文字符串进行编码,将编码后的结果设为Cookie值。读取时再解码。
Cookie c = new Cookie("cnName", java.net.URLEncoder.encode("孙悟空", "gbk"));
...
out.println(java.net.URLDecoder.decode(cookie.getValue()));
4.8 session
session代表一次用户会话。浏览器连接服务器开始,到浏览器与服务器断开为止,这个过程就是一次会话。
session通常用于跟踪用户的会话信息,如判断用户是否登录系统,或在购物车应用中跟踪用户购买的商品等。
session范围内的属性可以在多个页面的跳转之间共享,一旦关闭浏览器,即session结束,范围内属性全部丢失。
session对象是HttpSession的实例,有方法:
-
setAttribute(String attName, Object attValue)
-
getAttribute(String attName)
购物车应用的session://去除session范围的itemMap属性 Map<String, Integer> itemMap = (Map<String, Integer>)session.getAttribute("itemMap"); ... session.setAttribute("itemMap", itemMap); //将itemMap对象放到设置成session范围的itemMap属性
考虑session本身的目的,通常只应该把与用户会话状态相关的信息放入session范围内。如果仅仅为了两个页面交换信息,可以将该信息放入request范围内,然后forward请求即可。
session的属性值可以是任何可序列化的Java对象。
Servlet ( Servlet 3.1)
1.Serlvet开发
Servlet是个特殊的Java类,必须继承HttpServlet,每个Servlet可以响应客户端的请求,Servlet提供不同的方法用于响应客户端请求。
- doGet:响应GET请求
- doPost:响应POST请求
- doPut:响应PUT请求
- doDelete:响应DELETE请求
大部分时候,Servlet对于所有请求的响应都是完全一样的,此时可以采用重写一个方法来代替上面的几个方法:
只需重写service()方法即可响应客户端的所有请求。
另外HttpServlet还包含两个方法。
- init(ServletConfig config):创建Servlet实例时,调用该方法的初始化Servlet资源
- destroy():销毁Servlet实例时,自动调用该方法的回收资源
不用为Servlet编写构造器,如果需要对Servlet执行初始化操作,应将初始化操作放在Servlet的init()方法定义。如果重写了init(ServletConfig config)方法,则应在重写该方法的第一行调用super.init(config)。该方法将调用HttpServlet的init方法。
Servlet和JSP的区别:
- Servlet中没有内置对象,原来JSP中的内置对象都必须由程序显式创建。
- 对于静态的HTML标签,Servlet都必须使用页面输出流逐行输出。
2. Servlet配置
从Servlet 3.0开始,配置Servlet有两种方式:
- 在Servlet类中使用@WebServlet注解进行配置
- 通过在web.xml文件中进行配置
注解常用属性
属性 | 是否必须 | 说明 |
---|---|---|
asyncSupported | 否 | 指定该Servlet是否支持异步操作模式 |
displayName | 否 | 指定该Servlet的显示名 |
initParams | 否 | 用于为该Servlet配置参数 |
loadOnStartup | 否 | 用于将该Servlet配置成load-on-startup的Servlet |
name | 否 | 指定该Servlet的名称 |
urlPattern/value | 否 | 这两个属性的作用完全相同,都是指定该Servlet处理的URL |
使用注解,则需注意:
-
不要在web.xml文件的根元素中指定metadata-complete=“true”。
-
不要在web.xml文件中配置该Servlet。
@WebServlet(name="firstServlet", value="/firstServlet")
使用web.xml配置,需配置:
-
配置Servlet的名字:web.xml文件中的
-
配置Servlet的URL:web.xml文件中的
<servlet> <servlet-name>firstServlet</servlet-name> //Servlet名字 <servlet-class>servlet.FirstServlet</servlet-class> //Servlet的实现类 </servlet> <servlet-mapping> <servlet-name>firstServlet</servlet-name> <url-pattern>/aa</url-pattern> //Servlet映射的URL地址 <servlet-mapping>
3. JSP/Servlet的生命周期
创建Servlet实例有两个时机:
- 客户端第一次请求某个Servlet时,系统创建该Servlet的实例 ,大部分的Servlet都是这种Servlet
- Web应用启动时立即创建Servlet实例,即 load-on-startup Servlet
每个Servlet运行都有如下生命周期:
加载和实例化 ----> 初始化 ----> 请求处理 ----> 服务终止
-
- 创建Servlet实例
-
- Web容器调用Servlet的init方法,对Servlet进行初始化
-
- Servlet初始化后,将一直存在于容器中,用于响应客户端请求.如果客户端发送GET请求,容器调用Servlet的doGet方法处理并响应请求;如果客户端发送POST请求,容器调用Servlet的doPost方法处理并响应请求。或统一使用service()方法处理来响应用户请求。
-
- Web容器决定销毁Servlet时,先调用Servlet的destroy方法,通常在关闭Web应用之时销毁Servlet。
4. load-on-startup Servlet
应用启动时就创建Servlet,通常是用于某些后台服务的Servlet,或者需要拦截很多请求的Servlet,这种Servlet常作为应用的基础Servlet使用,提供重要的后台服务。
配置 load-on-startup的Servlet:
-
在web.xml中通过<servlet…/>元素的<load-on-startup…/>子元素进行配置
<servlet> <servlet-name>timerServlet</servlet-name> <servlet-class>servlet.TimerServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
-
通过@WebServlet注解的loadOnStartup属性指定
@WebServlet(loadOnStartup=1)
public class TimerServlet extends HttpServlet {public void init(ServletConfig config)throws ServletException { super.init(config); Timer t = new Timer(1000, new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { System.out.println(new Date()); } }); t.start(); }
}
4. 访问Servlet的配置参数
通过增加额外配置参数,可以实现更好的移植性:
访问Servlet配置参数通过ServletConfig完成,它提供:
java.lang.String getInitParameter(java.lang.String name):用于获取初始化参数
-
通过@WebServlet的initParams属性来指定
@WebServlet(name="testServlet", urlPatterns="/testServlet", initParams={ @WebInitParam(name="driver", value="com.mysql.jdbc.Driver"), @WebInitParam(name="url", value="jdbc:mysql://localhost:3306/javaee?useUnicode=true&characterEncoding=utf-8"), @WebInitParam(name="user", value="root"), @WebInitParam(name="password", value="1177") } ) ServletConfig config = getServletConfig(); String driver = config.getInitParameter("driver"); ...
-
通过在web.xml文件的<servlet…/>元素中添加<init-param…/>子元素来指定
<servlet> <servlet-name>testServlet</servlet-name> <servlet-class>servlet.TestServlet</servlet-class> <init-param> <param-name> <param-value> </init-param> ... </servlet> <servlet-mapping> <servlet-name>testServlet</servlet-name> <url-pattern>/testServlet</url-pattern> <servlet-mapping>
5. 使用Servlet作为控制器
Servlet作为表现出有三个劣势:
- 开发效率低,HTML标签由页面输出流完成
- 不利于团队协作开发,美工没法参与Servlet界面开发
- 程序可维护性差,修改代码必须重新编辑Java代码,并重新编译
在标准的MVC模式中,Servlet仅作为控制器使用,对于MVC模式的Java EE应用来说,JSP仅作为表现层(View)技术,其作用为:
- 负责收集用户请求参数
- 将应用的处理结果、状态数据呈现给用户
Servlet则仅充当控制器(Controller),作用类似于调度员:所有用户请求都发送给Servlet,Servlet调用Model来处理用户请求,并调用JSP来呈现处理结果;或者Servlet直接调用JSP将应用的状态数据呈现给用户。
Model通常由JavaBean来充当,所有业务逻辑、数据访问逻辑都在Model中实现。实际上隐藏在Model下的可能还有很多丰富的组件,如DAO组件,领域对象等。
JSP2的自定义标签
1. 自定义标签
自定义标签可以取代混乱的JSP脚本,因为在HTML页面中插入JSP脚本有如下坏处:
- JSP脚本非常丑陋,难以阅读
- JSP脚本和HTML代码混杂,维护成本高
- HTML页面中嵌入JSP脚本,导致美工人员难以参与开发
开发自定义标签:
-
- 开发自定义标签处理类
-
- 建立 .tld文件,每个 .tld文件对应一个标签库,每个标签库可包含多个标签
-
- 在JSP文件中使用自定义标签
1. 开发自定义标签类要求:
- 如果标签类包含属性,每个属性要有对应的getter和setter方法
- 重写doTag()方法,负责生成页面内容
2. 建立TLD文件
- taglib有3个子元素,tlib-version指定标签库实现版本,short-name指定默认短名,uri指定该标签库的URI。
- tag元素下可以有:
- name:标签的名称
- tag-class:指定标签的处理类
- body-content:指定标签体内容:
- tagdependent:指定标签处理类自己负责处理标签体
- empty:指定该标签只能作为空标签
- scriptless:指定该标签的标签体可以是静态HTML、表达式,但不能是JSP脚本
- dynamic-attributes:指定该标签是否支持动态属性
TLD文件放在WEB-INF路径或任意子路径下
3.使用标签库
在JSP页面指定使用标签:
- 标签库URI:确定使用哪个标签库
- 标签名:确定使用哪个标签
- 使用taglib编译指令导入标签库;
- 使用标签
taglib语法:
<%@ taglib uri=" " prefix=" " %>
使用标签语法:
<tagPrefix:tagName tagAttribute=" "... >
<tagBody/> //有标签体时
</tagPrefix:tagName>
2. 带属性的标签
对于有属性的标签,需要为<tag…/>元素增加<attribute…/>子元素,<attribute…/>子元素通常需指定如下子元素:
-
name:设置属性名
-
required:设置该属性是否为必须属性,值为boolean类型
-
fragment:设置该属性是否支持JSP脚本、表达式等动态内容,值为boolean类型
<tag> ... <attribute> <name>... <required>... <fragment>... </attribute> <attribute.../> <tag/>
在JSP页面使用:
<%@ taglib uri="" prefix=""%>
<mytag:query driver="" url="" user="" pass="" sql="" />
3. 带标签体的标签
可以在标签内嵌入 其他内容,包括静态或动态HTML内容,通常用于完成一些逻辑运算,如 判断和循环等。
带标签体的标签,配置时需要指定body-content为scriptless
4. 以页面片段作为属性的标签
与普通标签区别不大:
-
标签处理类中定义类型为JspFragment的属性
-
使用标签库时,通过jsp:attribute.../动作指令为标签的属性指定值
public class FragmentTag extends SimpleTagSupport{
private JspFragment fragment;
//getter/setter
…
public void doTag()throws JspException, IOException{
print("");
print("…
");
…
fragment.invoke(null); //调用、输出页面片段
}
}
在JSP页面使用:
<mytag:fragment>
<jsp:attribute name="fragment">
//动态的JSP页面片段
<mytag:nihao/> // or ${pageContext.request.remoteAddr}
</jsp:attribute>
</mytag:fragment>
5. 动态属性的标签
动态属性比普通标签多了两个要求:
-
标签处理类需要实现DynamicAttributes接口
-
配置标签时通过<dynamic-attributes…/>子元素指定该标签支持动态属性
public class DynamicAttributesTag extends SimpleTagSupport implements DynamicAttributes {
private ArrayList keys = new ArrayList();
private ArrayList values = new ArrayList<>();
public void doTag() throws JspException, IOException{
JspWriter out = getJspContext().getOut();
…
}
//动态添加属性
@Override
public void setDynamicAttribute(String uri, String localName, Object value)throws JspException {
keys.add(localName);
value.add(value);
}
}
配置标签时,需要指定<dynamic-attributes…/>子元素的值为true
在JSP页面使用时:
<mytag:dynamicAttr name="nihao" url="123"/> //指定两个属性
<mytag:dynamicAttr 书名="Java编程思想" 价格="99,00" 出版时间="2017"/> //指定三个属性
Filter
Filter主要用于对用户请求进行预处理,也可以第HttpServletResponse进行后处理,是个典型的处理链;Filter也可对用户请求生成响应。Filter与Servlet非常相似,有相同的生命周期、配置初始化参数,不同的是Filter可以同时拦截多个请求的URL。
Filter的使用流程为:
- Filter对用户请求进行预处理,
- 接着将请求交给Servlet进程处理并生成响应,
- 最后Filter再对服务器响应进行后处理。
Filter有如下几个用处:
- 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest
- 根据需要检查HttpServletRequest,也可修改HttpServketRequest头和数据
- 在HttpServletResponse到达客户端之前,拦截HttpServletResponse
- 根据需要检查HttpServletResponse,也可修改HttpServletResponse头和数据
Filter有如下几个种类:
- 用户授权的Filer:Filter负责检查用户请求,根据请求过滤用户非法请求
- 日志Filter:详细记录某些特殊的用户请求
- 负责解码的Filter:包括对非标准编码的请求解码
- 能改变XML内容的XSLT Filter等
- Filter可负责拦截多个请求或响应;一个请求或响应也可被多个Filter拦截。
创建一个Filter:
- 1.创建Filter处理类并实现javax.servlet.Filter接口
- 2.在web.xml文件中配置Filter
javax.servlet.Filter接口中定义了三个方法:
- void init(FilterConfig config):用于完成Filter的初始化
- void destroy():用于Filter销毁前,完成某些资源的回收
- void doFilter(ServletRequest request,ServletResponse response,FilterChain chain):实现过滤功能,该方法就是对每个请求及响应增加的额外处理。
配置Filter:
- 配置Filter名和拦截URL模式,可通过注解或web.xml文件配置,支持属性:
-
asyncSupported:是否支持异步操作
-
dispatcherTypes:仅对dispatcher模式的请求进行过滤,支持ASYNC、ERROR、FORWARD、INCLUDE、REQUEST这5个值得任意组合,默认为同时过滤5种模式请求
-
displayName:Filter得显示名
-
filterName:Filter得名称
-
initParams:配置参数
-
servletName:指定多个Servlet名称,用于指定该Filter仅对这几个Servlet执行过滤
-
urlPatterns/value:指定拦截得URL
@WebFilter(filieName="", urlPatterns="") <filter.../> <filter-name.../> <filter-class.../> <filter-mapping../> <filter-name.../> <url-pattern.../>
-
chain.doFilter(request, response):通过该方法实现是否放行用户请求
使用URL Rewrite实现网站伪静态
-
1.下载URL Rewrite的urlrewritefilter-4.0.3.jar,并放到WEB-INF的lib目录下
-
2.在web.xml中配置启用URL Rewrite Filter:
<filter> <filter-name>UrlRewriteFilter <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter <filter-mapping> <filter-name>UrlRewriteFilter <url-pattern>/*
-
3.在WEB-INF下增加urlrewrite.xml文件,该文件定义了伪静态映射规则
<urlrewrite> <rule> <from>/userinf-(\w*).html // $1代表上面第一个正则表达式所匹配的字符串 <to type="forward">/userinf.jsp?username=$1
现在,所有发向/userinf-(\w* ).html的请求都将被forward到userinf.jsp页面,并将(\w*)匹配的内容作为username参数值
Listener
- 定义Listener实现类,
- 通过注解或web.xml文件配置Listener
配置Listener的两种方式:
-
1.使用@WebListener修饰Listener实现类
-
2.在web.xml中使用<listener…/>元素配置
<listener.../> <listener-class.../>
常用Web时间监听器接口有:
- ServletContextListener:监听Web应用的启动和关闭
- ServletContextAttributeListener:监听ServletContext范围(application)内属性的改变
- ServletRequestListener:监听用户请求
- ServletRequestAttributeListener:监听ServletRequest范围内属性的改变
- HttpSessionListener:监听用户session的开始和结束
- HttpSessionAttributeListener:监听HttpSession范围内属性的改变
1.ServletContextListener 和 ServletContextAttributeListener
ServletContextListener接口包含方法:
- contextInitialized(ServletContextEvent sce):启动Web应用时,系统调用此方法
- contextDestroyed(ServletContextEvent sce):关闭Web应用时,系统调用此方法
例:在应用启动时获取数据库连接,并将渠道的连接对象Connection设置成application范围的属性,这样所有JSP页面都可通过application获取数据库连接
ServletContextAttributeListener接口包含方法:
- attributeAdded(ServletContextAttributeEvent event):把一个属性存入application范围时触发
- attributeRemoved(ServletContextAttributeEvent event):把一个属性从application范围删除时触发
- attributeReplaced(ServletContextAttributeEvent event): 替换application范围内属性时触发
2.ServletRequestListener 和 ServletRequestAttributeListener
ServletRequestListener接口包含方法:
- requestInitialized(ServletRequestEvent sre):用户请求到达、被初始化时触发
- requestDestroyed(ServletRequestEvent sre):用户请求结束、被销毁时触发
ServletRequestAttributeListener接口包含方法:
- attributeAdded(ServletRequestAttributeEvent event)
- attributeRemoved(ServletRequestAttributeEvent event)
- attributeReplaced(ServletRequestAttributeEvent event)
应用程序可以采用一个监听器类实现多个接口来监听多种事件
3.HttpSessionListener 和 HttpSessionAttributeListener
HttpSessionListener接口包含方法:
- sessionCreated(HttpSessionEvent se):用户与服务器的会话开始、创建时触发
- sessionDestroyed(HttpSessionEvent se):用户与服务器的会话断开、销毁时触发
例:可以监听每个用户会话的开始和断开,即监听系统的在线用户
HttpSessionAttributeListener接口包含方法:
- attributeAdded()
- attributeRemoved()
- attributeReplaced()
ServletContextAttributeListener / ServletRequestAttributeListener 和 HttpSessionAttributeListener 的作用相似,只是范围不同。
监听系统在线用户:
@WebListener
public class OnlineListener implements HttpSessionListener {
public void seesionCreated(HttpSessionEvent se){
HttpSession session = se.getSession();
ServletContext application = session.getServletContext();
String sessionId = session.getId();
if(session.isNew()){
String user = (String)session.getAttribute("user");
user = (user == null) ? "游客" : user;
Map<String ,String> online = (Map<String ,String>)application.getAttribute("online");
if(online == null){
online = new Hashtable<String, String>();
}
online.put(sessionId, user);
application.setAttribute("online", online);
}
}
public void sessionDestroyed(HttpSessionEvent se){
HttpSession session = se.getSession();
ServletContext application = session.getServletContext();
String sessionId = session.getId();
Map<String, String> online = (Map<String, String>)application.getAttribute("online");
if(online != null){
online.remove(sessionId);
}
application.setAttribute("online", online);
}
}
通过检查HttpServletRequest的做法可以更精确地监控在线用户地状态,如:sessionId、用户名、IP、正在访问的资源、访问时间等
…
JSP 2 特性
- 通过 <jsp-config…/><jsp-property-group…/> 直接配置JSP属性
- 表达式语言
- 简化的自定义标签API
- Tag文件语法
1.配置JSP属性
常用的属性:
-
:是否允许使用表达式语言,默认false,即允许使用
-
:是否允许使用JSP脚本,默认false,即允许使用
-
:声明JSP页面的编码
-
/:使用隐式包含,可以代替在每个页面里使用include编译指令来包含其他页面(分别为导入头和尾)
<jsp-config> <jsp-property-group> <url-pattern>*.jsp <el-ignored>false <page-encoding>GBK <scripting-invalid>false <include-prelude>/inc/top.jspf //隐式导入页面头 <include-coda>/inc/bottom.jspf //隐式导入页面尾
2.表达式语言
表达式语言是一种简化的数据访问方式,可以方便地访问JSP地隐含对象和JavaBeans组件,应该尽量使用表达式语言使JSP文件的格式一致,避免使用Java脚本
表达式语法:
${expression} //在需要输出$时,可使用转义 \$
2.1 支持算术、逻辑运算符
${7 * 7}
${10 mod 7} ${10 % 7} //求余
${(1 == 2) ? 3 : 4} //三目
且表达式语言将所有数值都当作浮点型处理
2.2 表达式语言的内置对象
-
pageContext:表示该页面的pageContext对象
-
pageScope:获取page范围的属性值
-
requestScope:
-
sessionScope:
-
applicationScope:
-
param:获取请求参数
-
paramValues:
-
header:获取请求头
-
headerValues:
-
initParam:获取请求Web应用的初始化参数
-
cookie:获取指定的Cookie值
<input type="text" name="name" value="${param['name']}"/> ${param.name} ${param["name"]} //两种方式获取请求参数值 ${header.host} ${header["accept"]} ${initParam["author"]} ${sessionScope["user"]} ${cookie["name"].value}
2.3 表达式语言的自定义函数
函数的本质是:提供一种语法允许在EL中调用某个类的静态方法
自定义函数的开发步骤:
-
1.开发函数处理类:即一个普通的类包含若干静态方法,每个静态方法都可定义成一个函数(JDK或其他项目中的类皆可,只要有静态方法)
public class Functions{ public static int countChar(String str){ return text.length(); } }
-
2.使用标签库定义函数,与定义标签方法相似。在<taglib…/>元素下增加<function…/>,每个<function…/>元素需要有3个子元素:
-
name: 自定义函数的函数名
-
function-class: 自定义函数的处理类
-
function-signature: 自定义函数对应的方法
<function.../> <name>countChar <function-class>*.Functions <function-signature>int countChar(java.lang.String)
-
-
3.在EL中使用自定义函数,需要先导入标签库
<%@ taglib prefix="myfunction" uri="" %> ${myfunction:countChar(param["name"])}
3.Tag File支持
更多推荐
所有评论(0)