Servlet与JSP基础知识

    技术2024-01-14  106

    Servlet

    1、什么是Servlet

    是sun公司制定的一种用来扩展web服务器功能的组建规范。 扩展web服务器功能:        web服务器(比如apache,iis等)只能够处理静态资源的请求,(即,需要事先将html、图片等资源准备好,并且存放到web服务器上),不能够处理动态资源的请求(需要通过计算,生成相应的htmL),所以需要扩展其功能。可以使用servlet来扩展web服务器的功能。当请求到达web服务器,如果需要计算,则web服务器调用servlet来处理。 什么是组件:符合一定规范,实现部分功能,需要部署到相应的容器里面才能运行的软件模块。 servlet就是一个符合servlet规范的组件,需要部署到servlet容器里面才能运行。 servlet只需要关注业务逻辑,servlet容器会提供运行环境(包括网络相关的服务)。 什么是容器:符合一定规范,为组件提供运行环境的一种程序。如:Tomacat,就是一个servlet容器

    2、如何写一个servlet

    *Step1:写一个java类,实现Servlet接口或者继承HttpServlet类(HttpServlet类实现了Servlet接口中的部分方法) *Step2:编译(使用javac命令将.java文件编译成.class文件) *Step3:打包 注:建立一个具有如下结构的文件夹(tomcat/webapps/examples) webapps WEB-INFO classes (.class文件) lib (.jar文件,该文件可选) web.xml (部署描述文件) *Step4:将step3创建好的整个文件夹拷贝到servlet容器指定的位置 (可以将整个文件夹使用jar命令压缩成 .war 后缀的文件) *Step5:启动容器,访问servlet。 http://ip:port/appname/url-pattern (url-pattern是一个字符串,在web.xml中设置)

    3、安装并且配置Tomcat (www.apache.org)

    下载压缩包,解压即可。 配置教程:https://www.cnblogs.com/dgj15222301178/p/7834815.html.

    4、servlet是怎么运行的

    比如输入:http://localhost:8080/dayo1/hello

    step1:浏览器依据 ip 和port 建立连接。

    step2:浏览器将相关数据添加到请求数据包里面,然后发送给服务器。

    step3:服务器会解析请求数据包中的数据,并且将这些数据添加到request对象里面,同时,还会创建一个response对象。

    注意: 开发人员可以通过request对象获得请求数据包中的数据,比如获得请求参数值。可以将处理结果写到response对象里面,容器会从response对象中获取处理结果,然后创建响应数据包并发送给浏览器。

    step4:服务器创建servlet对象(实例化),然后调用该对象的service方法。

    注意: 容器会将request对象和response对象作为参数传递过service方法。

    step5:服务器从response对象中获取处理结果,然后创建响应数据包并发送给浏览器。

    step6:浏览器解析响应数据包,依据解析到的数据生成相应的页面。

    5、常见错误

    404 404是一个状态码,表示服务器一依据请求路径找不到对应的资源 原因:请求路径写错 格式:http://ip:port/appname/url-pattern 应用没有部署或者部署失败 500 500是一个状态码,表示服务器运行出错。 原因:代码没有严格遵守servlet规范 比如:没有实现servlet接口或者继承HttpServlet类。 web.xml文件中将servlet-class写错或者servlet-name不一致 /*启动服务器失败可能是web.xml文件中出错(大小写或者不对应,或者类名写错)*/ 代码不严谨 比如:对请求参数没有做检查就做类型转换 405405是服务器找不到处理方法 service方法没有按照正确的格式来书写,即没有正确override HttpServlet的service方法

    http协议

    (1)什么是http协议

    网络应用层协议,规定了浏览器与web服务器之间如何通信以及相应的数据包的格式。 注: TCP/IP 属于网络层和传输层协议,负责将数据可靠地从一台机器传递到另外一台机器。 Http 属于应用层协议,将数据打包之后会将数据包交给tcp/ip来传递这些数据包。 (1) 浏览器与web服务器之间是如何通信        step1:建立连接。        step2:发送请求。        step3:发送响应。        step4:关闭连接。 如果浏览器要发送新的请求,需要重新建立新的连接,即“一次请求一次连接。”这样做的好处是服务器可以利用有限的连接尽可能完成多的请求服务。 ==(2)==数据包的结构    请求数据包:        请求行->请求方式 请求资源路径 通信协议        消息头->键值对 使用“: ”隔开,通信双方可以利用消息头发送一些特定的消息。比如浏览器可以通过发送user-agent消息头来告诉服务器,浏览器的类型和版本号。   实体内容->消息正文   响应数据包:        状态行->协议和版本 状态码 状态描述        注:状态码是一个三位数字,表示服务器处理请求的一种状态。    消息头->        注:服务器可以发送一些消息头给浏览器,比如:发送Content-Type消息头,告诉浏览器服务器返回的数据类型和编码方式。    实体类容->        注:程序处理的结果,浏览器会解析出来,生成相应的页面.

    (2)两种请求方式

    *GET请求: 哪些情况下,浏览器会发送get请求: 在浏览器地址栏输入某个地址 表单默认的提交方式 点击链接(超链接) 特点: 会将请求参数显示在浏览器地址栏,不安全 注:某些网络设备会记录请求地址;会将请求参数添加到请求资源路径的后面,只能提交少量的数据给服务器。 注:请求行大约只能存放2k左右的数据 *POST请求: 哪些情况下,浏览器会发送post请求: 将表单的method属性设置为post。 特点: 不会将请求参数显示在地址栏,相对安全一些。 注:http协议并不会对数据包中数据进行加密,所以,对于敏感数据,一定要加密。 会将请求参数添加到实体内容里面,可以提交大量的数据给服务器。

    (3)Servlet输出中文,如何处理乱码问题?

    xxx.println()方法默认会使用ISO-8859-1这个字符集来编码。如果是中文,则会发生编码错误,产生乱码问题。 解决方法: response.setContentType("text/html;charset=UTF-8"); //指定编码格式,分号隔开 读取请求参数值 1、String weight = request.getParameter("weight").trim(); 注:如果请求参数名与实际传递过来的请求参数名不一致,则会获得null值 2、String[] line = request.getParameterValues(String paramName); 注:有多个请求参数名相同时,使用此方法。对于多选框,如果没有选择任何选项,会获得null值, 处理流程中容易出现空指针异常。 处理空指针异常: if(line !=null){ for (String value : line) { System.out.println(value); } } 表单包含有中文参数值,如何处理乱码问题?
    1、为什么会有乱码
    表单提交时,浏览器会对中文参数值进行编码(比如,使用utf-8来编码), 服务器端默认会使用ISO-8859-1来解码,所以,会产生乱码。 注: 浏览器会使用打开该表单所在的页面时的字符集来进行编码 <!-- 模拟Content-Type消息头 相当于浏览器收到了一个Content-Type消息头, 浏览器会按照指定的字符集进行解码。 --> /*HTML指定字符集*/ <meta charset="UTF-8"> /*JSP指定字符集*/ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    2、如何解决
    POST请求: /* * 设置请求参数值的解码方式。 * 注: * a.该方法一定要添加到所有的getParameter方法的前面。b.该方法只针对post请求有效。 * 设置请求参数值的解码方式必须与html的编码方式相同才能解决乱码问题 * 此行代码必须写在service方法的第一行 * 该方法只针对POST请求方式有效 */ request.setCharacterEncoding("utf-8"); GET请求: 修改server.xml,<Connector URIEncoding="UTF-8"/> 注:如果是tomcat8.0及以上版本,可以不用加(只针对GET请求方式)
    3、POST与GET没有提交性能(效率)之分

    详细讲解:https://www.cnblogs.com/ljx20180807/p/10412427.html

    实操:
    访问数据库 *step1:建表 create database jsd1808db default character set utf8; use jsd1808db; create table t_user( id int primary key auto_increment, username varchar(50) unique, password varchar(20), email varchar(30) ); *step2:导包//jdbc与dbcp <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> </dependencies> *step3:添加jdbc.properties文件 *step4:添加DBUtils类并测试。 *step5:使用jdbc api访问数据库。 练习:写一个Servlet,以表格的形式显示所有用户的信息。 out.println("<table border='1' width='60%'>"); while(rs.next()){ int id = rs.getInt("id"); String username = rs... String pwd = .. ... out.println("<tr><td>" + id + "</td><td>" + username + "</td></tr>"); } out.println("</table>");

    DAO (扩展)

    (1)什么是DAO(Data Access Object)? 封装了数据访问逻辑的一个对象。 (2)如何写一个DAO? step1. 写一个java类,一般称之为值对象。 注: 该类用于存放从数据库中查询出来的数据。 比如,要查询t_user表中的数据,就可以设计一个User类,该类的结构要与表的结构一致,也就说,表有哪些字段,类就会有对应的属性,属性类型要匹配。 step2.写DAO类,提供一些访问数据库的方法。 (3)DAO的优点 方便测试: 将数据访问逻辑写在DAO类里面,可以直接测试,如果将数据访问逻辑写在servlet里面,需要部署整个应用才能测试。 方便代码的维护: DAO封装了数据访问逻辑,调用者不用关心底层数据库相关的代码,比如,数据库访问逻辑发生了改变(从jdbc换成了mybatis),对调用者没有任何影响。

    重定向<图redirect>

    (1)什么是重定向? 服务器通知浏览器向某个地址发送请求。 注: 服务器可以通过发送302状态码及location消息头(该消息头的值是一个地址,一般称之为重定向地址)给浏览器,浏览器收到之后,会立即向重定向地址发送请求。 (2)如何重定向? response.sendRedirect(String url); 例:response.sendRedirect("/WEB-INF/other.html"); 注: url就是重定向地址。 重定向之前,服务器会清空response对象上存放的所有数据。 该方法会自动设置状态代码302 (3)重定向特点 A.重定向的地址是任意的 response.sendRedirect(String url); //String url任意地址 B.重定向之后浏览器的地址栏会发生改变 地址变为从定向的的地址

    JSP

    什么是JSP

    jsp是sun公司制定的一种服务器端的动态页面技术规范。       servlet也可以生成动态页面,但是过于繁琐,需要使用out.println语句来输出,并且不利于页面的维护,修改页面就需要修改java代码,所以sun公司才推出了jsp规范。       jsp是一个以.jsp为后缀的文件(主要内容是html和少量的java代码),容器会将这个文件转换成一个对应的servlet然后执行。也就是说jsp的本质就是一个servlet。       .jsp文件可以包含:html css js java 代码

    如何书写JSP文件

    step1:添加一个以.jsp为后缀的文件 step2:在该文件里面添加如下内容: 1、html,css,js 直接写即可 2、java代码 语法一:java代码片段 <% javaCode %> 直接使用隐含对象 在jsp文件里面可以直接使用的隐含对象 9个内置对象:" page config out request response session application pageContext exception " 因为容器会自动添加获得这些对像的代码。

    什么是指令

    可以通过指令告诉容器,在将jsp转换成servlet时,做一些额外的处理,比如导包。 指令语法 <%@ 指令名 属性=值 属性=%>:如果有多个属性用空格隔开。 page指令 import属性:指定要导的包名,如果有多个包,用","号隔开。 比如: <%@ page import="java.util.*,java.text.*"%> contentType属性:设置response.setContentType的内容。 pageEncoding属性:告诉容器,在读取jsp文件的内容时,使用指定的字符集来解码。 例: contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" include指令 <%@ include file="" %>: file属性用于指定被包含的文件名。 该指令用来告诉容器,在将jsp转换成servlet时,将file属性指定的文件的内容插入到该指令所在的位置。 被包含的文件可以是任何文件,包括html,如果是jsp,该jsp并不会执行! taglib指令 <%@ taglib uri="tagLibraryURI" prefix="tagPrefix" %> uri="tagLibraryURI"指明标签库文件的存放位置。prefix="tagPrefix"表示该标签使用时的前缀

    如何书写java代码

    第一种: <%@ page 导入包 %> //导入需要的包,用逗号隔开 例:<%@ page import="DAO.UserDAO,entity.User,java.util.*"%> <% java代码 %> //java代码片断,多行逻辑代码 例:<% Date date=new Date(); String str="yyyy-MM-dd HH:mm:ss"; /* HH:mm:ss*/ SimpleDateFormat sdf=new SimpleDateFormat(str); String line=sdf.format(date); out.println(line); %> 第二种: <%= java表达式 %> //jsp表达式,单据执行语句,有返回值 例:<%=user.getId() %> 第三种: <%! Java代码 %> //jsp数据定义,类定义 例: <%! String str="<h2>JSP数据定义</h2>"; %>

    JSP如何运行

    阶段一: 容器先将jsp转换成一个servlet. html,css,js -->在service方法里面,使用out.write输出 <% %> -->在service方法里面,照搬 <%= %> -->在servlet方法里面,等效于使用out.println输出 阶段二: 容器调用该servlet,执行相应业务方法。

    转发

    *什么是转发:(图forward.png) 一个web组件将未完成的处理交给另外一个web组件继续做。 注: web组件指的是servlet和jsp的统称。 常见的情况是一个servlet获得数据之后,转发给一个jsp来展现这些数据。 *如何转发 step1:绑定数据到请求对象上 request.setAttribute(String name,Object obj);: name称之为绑订名,obj称之为绑订值。内部的实现,实际上是将数据放到了一个map对象里面。 step2.获得转发器 RequestDispatcher rd = request.getRequestDispatcher(String uri);: a.RequestDispatcher是一个接口,该方法会返回一个实现了该接口的对象(即转发器)。 b.uri是转发的目的地,通常是一个jsp的地址。 c.RequestDispatcher可以理解为是一个媒介,web组件可以通过RequestDispatcher来通知容器去调用另外一个web组件。 d.转发的本质是一个web组件通知容器去调用另外一个web组件。 step3.转发 rd.forward(request,response); *转发的特点 a.转发之后,浏览器地址栏的地址不变。 b.转发的目的地有限制,要求属于同一个web应用。 例子: List<User> users = dao.findAll(); /** * 绑定数据到请求requst对象上 */ request.setAttribute("users", users); //绑定值可以是任意的数据 /** * 获得转发器 * 请求list的时候可以直接响应NewListUser.jsp */ RequestDispatcher rd=request.getRequestDispatcher("NewListUser.jsp"); /** * 转发(调用转发器的forward方法) */ rd.forward(request, response);

    转发与重定向比较

    A:浏览器地址栏的地址有无变化?       重定向之后,浏览器地址栏的地址会发生变化;       转发之后,浏览器地址栏的地址不变。 B:目的地有无限制?       重定向地址没有任何限制,转发有限制(要求属于同一个web应用)。 C:能否共享request对象?       转发所涉及的各个web组件可以共享同一个request对象,重定向不行。       注:             c1.容器收到请求之后,会立即创建request对象和response对象,一旦响应发送完毕,容器会立即删除这两个对象。             即request对象和response对象的生存时间很短暂(在一次请求与响应期间存在)。             c2.重定向是两次请求,上次请求创建的request对象和response对象已经被删除。 D:转发是一件事没有做完,让另外一个web组件继续做;而重定向是 一件事已经完成,去做另外一件独立的事。

    Cookie && Session

    Cookie:将状态保存在浏览器端

    1、状态管理 什么是状态管理: 将浏览器与web服务器之间多次交互当做一个整体来处理,并且将多次交互所涉及到的数据(即状态)保存下来。 如何进行状态管理 方式一:将状态保存在浏览器端(使用cookie) 方式二:将状态保存在服务器端(使用session) (1)Cookie: 什么是Cookie:服务器临时存放在浏览器端的少量数据,用于存放用户的状态。 注:当浏览器第一次访问服务器时,服务器会将少量数据以Set-Cookie消息头的形式发送给浏览器,浏览器会将这些数据保存下来。当浏览器再次访问服务器时,会将这些数据以cookie消息头的形式发送给服务器。 "Cookie存放在内存中,当关闭浏览器之后,内存中的内容被清除,当再次打开浏览器直接请求findCookie,服务器返回not find Cookie!"2)如何添加Cookie Cookie cook=new Cookie(String name,String value); response.addCookie(c); Cookie只能存放字符串 cookie都有一个名字,值也是一个字符串。 例子: /** * 向浏览器端发送一个名称为username的cookie * 注:cookie只能存放字符串 * 可以同时发送多个Cookie */ Cookie cook=new Cookie("username","Sally"); response.addCookie(cook); Cookie cook1=new Cookie("City","BeiJing"); response.addCookie(cook1);3)如何读取Cookie 方法:Cookie[] request.getCookies(); 有可能该方法的返回值为null 获取Cookie的方法: String name = cook.getName(); String value = cook.getValue(); 例子: /* 读取浏览器端发送送过来的cookie. 一个Cookie对象封装了一个cookie的信息。 * 注:有可能返回值为Null(浏览器第一次请求时为空) */ Cookie[] cookies=request.getCookies(); if(cookies!=null){ for(Cookie cook: cookies){ String name=cook.getName(); String value=cook.getValue(); //设置cook的值 cook.setValue("ShangHai"); out.println("name="+name+" value="+value); } }else{ //没有找到cookie out.println("Not find Cookie!"); }4)Cookie的生存时间 默认情况下,浏览器会将Cookie存放到内存中里面,浏览器关闭,则Cookie会被删除。 //设置生存时间 cookie.setMaxAge(int seconds); 单位:秒 seconds >0:浏览器会将cookie保存在硬盘上(一般是一个很小的文件),超过指定时间,浏览器会将cookie删除。 seconds <0:缺省值(浏览器会将cookie存放到内存里面) seconds =0:浏览器会删除该cookie 比如:要删除一个名称为username的cookie:(同名替换原来的cookie) Cookie c = new Cookie("username",""); c.setMaxAge(0); response.addCookie(c);5)Cookie的编码问题 Cookie只能存放合法的ASCII字符,如果需要存放中文,需要将中文转换成对应的ASCII字符的形式(即编码)。 String str=URLEncoder.encode(String str,String charset); 建议在添加/获取Cookie时统一做编码处理: 编码: Cookie cook1=new Cookie("City",URLEncoder.encode("北京","UTF-8")); 解码: String value=URLDecoder.decode(cook.getValue(),"UTF-8");6)Cookie的路径问题 什么是Cookie的路径问题: 浏览器在向服务器发请求时,会比较请求地址是否符合Cookie的路径,只要符合条件的cookie才会发送给服务器。 Cookie的默认路径 等于添加该Cookie的web组件的路径,比如: /day06/biz01/addcookie.jsp 则该jsp添加的cookie,则该cookie的路径就是"/day06/biz01"7)匹配规则 请求地址要么等于cookie的路径,要么是其子路径,符合该要求的cookie会被发送。 比如,cookie的路径是"/day06/biz01","/day06/findCookie1.jsp" no "/day06/biz01/findCookie2.jsp" yes "/day06/biz01/sub/findCookie3.jsp" yes "/day06"下的cookie都会被发送 (8)修改Cookie路径 cookie.setPath(String uri); "cookie的路径不一样时,可以出现名称相同"9)Cookie的限制 Cookie可以被用户禁止。(在浏览器上设置) Cookie不安全。(浏览器上可以查看) cookie是一种客户端的状态管理技术,数据都保存在浏览器端,所以对于敏感数据,一定要加密处理。 Cookie只能保存少量数据。(4k左右) Cookie的数量也有限制。(大约几百个) Cookie只能存放字符串。

    Session:将状态保存在服务器端

    什么是Session: 服务器端为了保存用户的状态而创建的一个特殊的对象。 注: 当浏览器第一次访问服务器时,服务器创建一个特殊的对象(该对象一般称之为session对象,session对象有一个唯一的id,一般称之为sessionId)。 服务器会将sessionId以cookie的方式发送给浏览器。当浏览器再次访问服务器时,会将sessionId会送过来,服务器可以依据sessionId找到对应的session对象。 1、如何获得Session对象 (1)方式一 HttpSession session = request.getSession(boolean flag): HttpSession是一个接口。 当flag为true: 先查看请求当中是否有sessionId,如果没有,则创建一个session对象。如果有, 则依据sessionId查找对应的session对象,找到了则返回该对象,找不到, 则创建一个新的session对象。 session.invalidate(); //删除session对象,能找到session对象,但是没有任何数据 当flag为false: 先查看请求当中是否有sessionId,如果没有,返回null。如果有, 则依据sessionId查找对应的session对象,找到了则返回该对象,找不到,返回null。 (2)方式二 HttpSession session = request.getSession(); 注: 等价于request.getSession(true); 2、Session对象的常用方法 绑定数据 session.setAttribute(String name,Object obj); //可以绑定多个数据(属性) 例子: session.setAttribute("count", "1"); session.setAttribute("name", "Mr_Huang"); 依据绑定名获得绑定值,如果绑定值不存在则返回null Object session.getAttribute(String name); 例子: Date date=(Date)session.getAttribute("date"); Integer count=(Integer)session.getAttribute("count"); 解除绑定 session.removeAttribute(String name); //将该属性从session中移除 "练习" 显示用户上一次访问的时间,如果是第一次访问,显示“你是第一次访问”。 3、session 超时 服务器会将空闲时间过长的session对象删除掉。目的是为了节省内存空间。 注:大部分服务器默认的超时时间限制是30分钟。 4、如何修改超时时间 方式一 修改服务器的配置文件(web.xml) <session-config> <session-timeout>30</session-timeout> </session-config> 方式二 session.setMaxInactiveInterval(int seconds); //单位:秒 设置两次请求之间的最大时间间隔,如果超过这个时间,服务器端的session对象会被销毁。 5、删除session session.invalidate(); //失效 6、session验证 step1. 登录成功以后,在session对象上绑订一些数据。比如: session.setAttribute("user",user); step2. 当用户访问需要保护的资源时(即只有登录之后的用户才能访问的 资源),进行session验证: Object obj = session.getAttribute("user"); if(obj == null){ //没有登录,重定向到登录页面 response.sendRedirect("login.jsp"); return; //结束当前方法 } 7、比较session 与 cookie session 支持更丰富的数据类型,更安全,可以存放更多的数据; 但是session是将状态保存在服务器端,有可能会占用过多的内存。 cookie 只能存放字符串,数据保存在浏览器端,不安全,只能存放少量数据。 8、地址\路径问题 相对路径: 不以"/"开头的都是相对路径。 绝对路径: 以"/"开头的路径,就是绝对路径。 如何写绝对路径: 链接、表单提交、重定向:从应用名开始写 <a href="<%=request.getContextPath() %>/a2.jsp">访问a2(使用request.getContextPath()</a> <form action="<%=request.getContextPath() %>/path" method="POST"> response.sendRedirect(request.getContextPath()+"/jsp03/sub/a4.jsp"); //重定向 转发:从应用名之后开始写(省略了应用名) request.getRequestDispatcher("/jsp03/sub/a4.jsp").forward(request, response); //转发 不建议将应用名直接写在路径里面,而应该使用下面这个 request.getContextPath(); //获取实际部署应用名的绝对路径 方法来获取应用名绝对路径。 建议使用绝对路径,容易写,而且利于维护。

    Servlet生命周期

    什么是servlet的生命周期: 指的是容器如何去创建servlet对象,如何对该对象进行初始化,如何调用该对象处理器请求,以及如何销毁该对象的整个过程。 即:Servlet容器是如何管理Servlet的。 创建、初始化、调用、销毁 生命周期分成那几个阶段: 1、实例化 什么是实例化:容器调用servlet的构造器创建servlet对象。 什么时候实例化: 1、默认情况下,容器收到请求之后才会创建。 注:容器只会创建一个实例(对象) 2、容器启动之后,立即创建 注:需要配置 load-on-startup 参数 例如:<servlet> <servlet-name>life_servlet</servlet-name> <servlet-class>web.LifeServlet</servlet-class> <!-- 配置启动加载,容器启动之后会立即创建Servlet实例。 参数值要求大于等于0的整数,容器会依据值从小到大的顺序加载, 即:优先级(值越小优先级越高) --> <load-on-startup>1</load-on-startup> </servlet> 2、初始化 什么是初始化 指的是容器在创建servlet实例之后,会调用该实例的init方法。 注:init方法只会执行一次。 GenericServlet类里面提供了init方法的实现。 该方法会将容器传递过来的ServletConfig对象保存下来,并且提供了 一个方法(getServletConfig)来获得该对象。 Config对象用于获取配置参数的值。 初始化参数。 <!-- 配置初始化参数 书写在servlet里面 --> <servlet> <init-param> <param-name>company</param-name> <param-value>IBM</param-value> </init-param> </servlet> /* 通过ServletConfig对象提供的方法来读取初始化参数值。*/ String company = config.getInitParameter("company"); //IBM 如何实现自已的初始化处理逻辑。 只需要重写(override) GenericServlet的init()无参方法。 3、就绪 容器收到请求之后,调用servlet对象的service方法。 即:调用service方法处理请求。 GenericServlet类里面提供了init方法的实现。 该方法是这样实现的: 依据请求类型调用对应的doXXX方法, 比如:get请求会调用doGet方法,post请求会调用doPost方法。 doGet、doPost方法只是抛出了一个异常。 开发人员可以重写(override) HttpServlet的doXXX方法来实现 自定义业务逻辑的处理。也可以重写 HttpServlet的service方法。 4、销毁 什么是销毁 容器在删除servlet对象之前会调用该对象的destroy方法。 该方法只执行一次! *相关的接口与类: Servlet接口 该接口主要声明了三个方法: init(ServletConfig config); service(ServletRequest req,ServletResponse res); destroy(); GenericServlet抽象类 实现了Servlet接口中的部分方法(init,destroy) HttpServlet抽象类 继承了GenericServlet,实现了service方法。 *容器如何处理请求资源路径 比如,在浏览器地址栏输入http://ip:port/day08-2/abc.html, 浏览器会将"/day08-2/abc.html"作为请求资源路径发送给容器。 *step1.容器默认认为访问的是一个servlet,容器会从web.xml中去查找对应的servlet。 将请求资源路径中的应用名除掉,然后去跟<url-pattern>的值去做匹配。 url-pattern有三种写法: 1、精确匹配: 即请求资源路径除掉应用名之后的值必须等于url-pattern的值。 (比如这儿,请求资源路径除掉应用名之后是 "/count",url-pattern的值正好也是"/count",这样就匹配了) <url-pattern>/count</url-pattern> 2、通配符匹配: 使用"*"匹配任意的零个或者多个字符。 比如: <url-pattern>/*</url-pattern> */ /不能省略,用于匹配/后面的任意内容 3、后缀匹配: 使用"*."开头,然后接一个后缀(后缀就是一个字符串).注意:后缀匹配前面没有 / (反斜杠) 比如: <url-pattern>*.do</url-pattern> 以上配置,会匹配所有以 .do 结尾的请求。 //http://ip:port/day08-2/abc.do <url-pattern>*.do</url-pattern> *step2.如果没有匹配的servlet,容器会从对应的位置去查找文件, 如果找不到,返回404

    Filter && Listener

    过滤器

    作用:检测用户提交数据是否满足会定的要求。比如:用户名、密码、邮箱.... 什么是过滤器 servlet规范中定义的一种特殊组件,用于拦截servlet容器的调用过程。 注: Servlet容器收到请求之后,会先调用过滤器,在调用servlet。(执行顺序) 如何写一个过滤器 *step1:写一个java类,实现Filter接口。 *step2:在doFilter方法当中,实现拦截处理逻辑(同时重写init、destroy、doFilter方法) 注意强制转换: HttpServletRequest request=(HttpServletRequest)arg0; HttpServletResponse response=(HttpServletResponse)arg1; *step3:配置过滤器。(web.xml)

    过滤器的优先级

    当有多个过滤器都满足拦截要求,则容器依据<filter-mapping> 配置的先后顺序来执行。 例子: public class CommentFilter implements Filter { private FilterConfig config; /**容器启动之后会立即创建过滤器实例。只会创建一个实现!*/ public CommentFilter(){ System.out.println("CommentFilter's constructor!"); } /**容器在删除过滤器之前会调用destroy方法,发方法只执行一次。*/ public void destroy() { System.out.println("CommentFilter's destroy..."); } /** * 容器收到请求之后,会调用doFilter方法来处理。 * (类似于Servlet的service方法) * 因为sun公司的过度设计,所以在doFilter方法里面开发人员需要做强制转换。 * ServletRequest是HttpServletRequest的父接口 * ServletResponse是HttpServletResponse的父接口 * FilterChain(过滤链) * 如果调用了过滤器链的doFilter方法,表示继续向后调用 * (即:继续调用后续的过滤器,最后调用Servlet的service方法) * 如果没有调用过滤器的doFilter方法,则不会再向后调用,而是返回处理结果。 */ public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain)throws IOException, ServletException { /** 强制转换 */ HttpServletRequest request=(HttpServletRequest)arg0; HttpServletResponse response=(HttpServletResponse)arg1; System.out.println("CommentFilter's doFilter begin..."); request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); if(CheckWords(request)){ response.getWriter().println("评论内容包含违禁字!"); }else{ //继续向后调用 chain.doFilter(request, response); } System.out.println("CommentFilter's doFilter Over!"); } /** * 实例化之后,容器会调用init方法,该方法只会执行一次。 * FilterConfig可以用来读取过滤器初始化配置参数(值)。 */ public void init(FilterConfig arg0) throws ServletException { System.out.println("CommentFilter's init ..."); //将容器传递过来的FilterConfig保存到成员变量中,作为全局变量使用。 config=arg0; } /** * 获取配置违禁字的参数值,并且判断用户输入的内容是否包含违禁字。 * 返回boolean类型的值。 * @param request * @return */ public boolean CheckWords(HttpServletRequest request){ boolean flag=false; String content=request.getParameter("content"); String illegal = config.getInitParameter("illegal"); for(int i=0;i<content.length();i++){ if(illegal.indexOf(content.charAt(i)) !=-1){ flag=true; } } return flag; } }

    过滤器的优点

    1、可以在不修改原有代码的基础上,为应用添加一些简单的功能。      “开闭原则”:对修改关闭,对扩展开放 2、可以将多个组件相同的功能集中写在过滤器里面,方便代码的维护。

    监听器

    *什么是监听器 Servlet规范当中定义的一种特殊的组件,用于监听servlet容器产生的事件并进行相应的处理。 注: 容器会产生两大类事件: 1、生命周期相关的事件 当容器创建或者销毁 request、session 、servlet上下文时产生的事件。 2、绑定数据相关的事件 当调用了request,session,servlet上下文的setAttribute,removeAttribute时产生的事件。 *Servlet上下文 什么是Servlet上下文 容器启动之后,会为每一个web应用创建一个唯一的一个符合ServletContext接口要求的对象,该对象我们一般称之为Servlet上下文。 该对象有两个特点: 1、唯一性:一个web应用对应一个servlet上下文 2、持久性:只要容器不关闭,应用没被卸载,则ServletContext会一直存在。 *如何获得servlet上下文 可以通过ServletConfig,FilterConfig,GenericServlet,HttpSession 提供的getServletContext方法来获得。 *作用 绑定数据 setAttribute(String name,Object obj); Object getAttribute(String name); removeAttribute(String name); 注: request session servletContext 都提供了绑定数据的相关方法,区别如下: 区别1:绑定的数据生存时间不一样,从小到大一次是 request < session < servletContext.在满足使用条件的情况下优先使用生命周期短的。 区别2:绑定到session对象上的数据只有与之对应的用户才能够访问;绑定到servlet上下文上的数据所有用户都能访问到。 读取全局的初始化参数 <!-- 配置全局的初始化参数 --> <context-param> <param-name>company</param-name> <param-value>IBM</param-value> </context-param> //读取全局的初始化参数 ServletContext sctext=getServletContext(); String company = sctx.getInitParameter("company");

    如何写一个监听器

    1、写一个java类,实现相应的监听器接口(8种监听事件) 要依据监听的事件类型来选择实现对应的接口 比如:要监听session对象的创建和销毁,就需要实现HttpSessionListener接口 public class CacheListener implements ServletContextListener{ public void contextDestroyed(ServletContextEvent arg0) { System.out.println("CacheListener's contextDestroyed...删除servlet上下文"); ServletContext sctext=arg0.getServletContext(); sctext.removeAttribute("users"); } public void contextInitialized(ServletContextEvent arg0) { System.out.println("CacheListener's contextInitialized...servlet上下文绑定数据!"); ServletContext sctext=arg0.getServletContext(); @SuppressWarnings("unchecked") //I don't know! List<User> users=(List<User>)sctext.getAttribute("users"); if(users==null){ try { dataAccessObj dao=new dataAccessObj(); users = dao.findAllData(); sctext.setAttribute("users", users); System.out.println("绑定users数据成功!"); } catch (SQLException e) { e.printStackTrace(); //将异常包装之后抛给容器(抛出的的异常必须小于等于父类的异常) throw new RuntimeException(e); } } } } 2、在监听器接口的方法当中,实现监听处理逻辑 //**************************** 3、配置监听器(web.xml) <!-- 配置监听器 --> <listener> <listener-class>web.CacheListener</listener-class> </listener> 异常抛出给容器处理 //将异常包装之后抛给容器(抛出的的异常必须小于等于父类(接口)的异常) throw new RuntimeException(e); 配置web.xml文件 <!-- 配置抛出给容器的异常,状态码与异常类只能写一个 --> <error-page> <error-code>500</error-code> <!-- <exception-type>java.sql.SQLException;</exception-type> --> <location>/throwerror.jsp</location> </error-page>

    Servlet的线程安全问题

    为什么说Servlet会有线程安全问题? 容器只会创建一个实例。 容器收到请求就会启动一个线程,由该线程来进行相应的处理。这样就有可能有多个线程同时去调用同一个Servlet对象的service方法,就有可能产生线程安全问题。 比如说:这些线程同时去修改servlet的某个属性。 如何解决线程安全问题? /*对有可能产生线程安全问题的代码块加锁。加锁会影响性能。*/ synchronized(this){ count ++; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println( Thread.currentThread().getName()+":" + count); }

    Servlet总结问题

    (1)Servlet基础      1).什么是Servlet?      2).如何写一个Servlet?      3).Servlet是如何运行的?      4).Http协议(了解)          a.http协议是什么?          b.特点?          c.数据包的结构(消息头、状态码)          d.两种请求方式 (2)Servlet核心      1).如何获得请求参数值?      2).Servlet输出中文,如何处理?      3).表单包含有中文参数,如何处理?      4).Servlet容器如何处理请求资源路径?      5).如何让一个Servlet处理多种请求?      6).Servlet的线程安全问题      7).转发与重定向          a.什么是重定向?          b.如何重定向?          c.重定向的特点          d.什么是转发?          e.如何转发?          f.转发的特点          g.比较转发与重定向      8).Servlet的生命周期          a.什么是Servlet的生命周期?          b.生命周期分成哪几个阶段?          c.容器在什么时候创建Servlet对象?(load-on-startup)          d.容器会创建几个Servlet实例?。          e.初始化方法会执行几次?          g.如何配置初始化参数?          h.如何实现自已的初始化处理逻辑?          i.doGet,doPost方法的作用?          j.Servlet接口,GenericServlet,HttpServlet的关系。          h.ServletConfig的作用?      9)路径问题          a.什么是相对路径?          b.什么是绝对路径?          c.如何写绝对路径?      10)Servlet上下文          a.什么是Servlet上下文? (唯一性、持久性)          b.如何获得Servlet上下文?          c.主要作用(绑订数据时与request,session的区别)          d.全局的初始化参数。 (3)状态管理      1)什么是状态管理?      2)如何进行状态管理?      3)Cookie          a.什么是Cookie? (set-cookie,cookie)          b.如何添加Cookie?          c.添加Cookie时需要考虑的三个问题(编码问题、生存时间、路径问题)。          d.如何读取Cookie?          e.Cookie的限制      4)Session          a.什么是Session?          b.如何获得Session对象?          c.常用方法。          d.Session超时          e.删除Session对象          f.比较Cookie与Session (4)过滤器与监听器      1)什么是过滤器?      2)如何写一个过滤器?      3)过滤器的优先级      4)初始化参数      5)过滤器的优点      6)什么是监听器?      7)如何写一个监听器? (5)数据访问 (扩展)      1)什么是DAO?      2)如何写一个DAO?      3)DAO的优点? (6)典型案例      用户管理      登录(session验证)

    JSP详解

    1.jsp基础

    (1)什么是jsp? sun公司制订的一种服务器端的动态页面技术规范。 注:.jsp为后缀的文件, 会被容器转换成一个对应的servlet。 jsp的本质就是一个servlet! (2)如何写一个jsp文件? 1)html(css,js) 直接写即可 2)java代码 a. java代码片断 <% java代码  %> b. jsp表达式 <%= java表达式 %> c. jsp声明 (a1.jsp) <%! 声明一个变量或者方法 %> 例子: <%! String str="JSP数据定义测试"; /* 带有修饰符的方法,修饰符可有可无 */ public String method(){ return str; } /* 不带修饰符的方法 */ int sum(int x,int y){ return x+y; } %> <%=method()%> <%="求和计算:"+sum(5,8) %> (3)隐含对象 a.什么是隐含对象? 直接可以使用的对象。 b.为什么可以直接使用这些隐含对象? 容器会自动添加获得这些对象的代码。 c.有哪些隐含对象? out,request,response session,application "这些常用" pageContext:页面上下文 (a2.jsp,a3.jsp) 容器会为每一个jsp实例创建唯一的一个符合PageContext 接口要求的对象,该对象会一直存在,除非jsp实例被容器删除。 该对象的作用主要有两个: 作用1:绑订数据。 绑订到pageContext上的数据,只有对应的jsp实例(当前页面JSP)能够访问到。 作用2:提供了一些方法,用来获得其它所有的隐含对象 例子: <body> <% /* 隐含对象:pageContext,绑定的数据只有当前页面可以访问,其它的页面无法访问 */ pageContext.setAttribute("username","Mr_Huang"); %> <%=pageContext.getAttribute("username") %> </body> config::ServletConfig(a4.jsp) 可以为JSP配置初始化参数,然后通过config对象去获取。 <body> <%=config.getInitParameter("company") %> </body> 配置文件: <servlet> <servlet-name>a4</servlet-name> <jsp-file>/a4.jsp</jsp-file> "jsp-file 实现把jsp转换为servlet" <init-param> <param-name>company</param-name> <param-value>Mr_Huang</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>a4</servlet-name> <url-pattern>/a4</url-pattern> </servlet-mapping> exception:(a5.jsp,a6.jsp) 当page指令的isErrorPage属性值设置为true时,可以使用该隐含对象, 该隐含对象可以用来获得jsp运行时产生的一些异常的简短的描述。 a5.jsp:<%@ page errorPage="a6.jsp"%> "将异常处理转到a6.jsp页面处理" <body> 传入参数:http:ip:port/day11/a5.jsp?number=123 <% String number=request.getParameter("number"); /* 暂时不用接收 */ int num=Integer.parseInt(number); out.println(num); %> </body> a6.jsp:<%@ page isErrorPage="true" %> <body> 请输入合法的数值!<br> <%=exception.getMessage() %><br> <%=exception.toString() %> </body> page(了解): jsp实例本身(jsp对应的servlet实例)(4)jsp是如何执行的 step1. 容器要将jsp转换成一个servlet html(css,js) ---> 在service方法里面,使用out.write输出。 <% %> -----> 照搬到service方法里面。 <%= %> -----> 在service方法里面,使用out.print输出。(等效:out.println()) <%! %> -----> 为servlet增加新的属性或者新的方法。 (5)指令 什么是指令: 可以通过指令告诉容器,在将JSP转换成servlet时,做一些额外的处理,比如导包。 有哪些指令: page指令: import属性:导包 <%@ page import="java.util.Date" %> pageEncoding属性:指定jsp文件的编码集 language属性:指定代码使用的语言种类 <%@ page language="java" pageEncoding="UTF-8"%> contentType属性:response.setContentType方法的内容(文件类型,以及编码) <%@ page contentType="text/html; charset=UTF-8" %> errorPage属性:指定一个异常处理页面。当jsp运行发生异常时,容器会调用该异常处理页面。 <%@ page errorPage="a6.jsp"%> isErrorPage属性:默认值是false,如果值为true,就可以使用exception隐含对象。 <%@ page isErrorPage="true" %> <%=exception.toString() %> session属性 (a7.jsp):默认值是true,如果值为false,(页面)不能够使用session隐含对象。 <%@ page session="true" %> include指令: file属性:指定被包含的文件 <%@ include file="header.jsp" %> taglib指令: 导入需要使用的jsp标签 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> uri:是要导入的jsp标签的命名空间,指明标签库文件存放的路径(如:域名) 注:命名空间是为了区分同名的元素而在元素前添加的一段说明,通常是一个域名。 prefix:前缀,命名空间的别名。 <short-name>c</short-name> <uri>http://java.sun.com/jsp/jstl/core</uri> (6)注释(a8.jsp) <!-- 注释内容 --> 如果注释的内容是java代码,java代码会被执行;但是同时也是html注释,会被浏览器忽略掉. <%-- 注释内容 --%> 如果注释的内容是java代码,java代码不会被执行 javaBean 是一个规范,满足如下几个条件就可以称之为javaBean: publicpublic 构造器 实现Serializable接口(最好) 有一些属性以及对应的get/set方法

    2.JSP标签和el表达式

    jsp标签是什么

    jsp标签是sun公司推出的一个规范,目的是为了替换jsp中的java代码。 jsp标签语法类似于html标签(比如说,有开始标记、结束标记、有一些属性、有标签体)。 容器遇到jsp标签之后,会调用jsp标签对应的jsp标签类中的java代码。 使用jsp标签,好处是,jsp文件便于美工去修改,另外,也便于代码的复用(jsp标签可以重用)。 el表达式是什么 一套简单的运算规则,用于给jsp标签的属性赋值,也可以脱离jsp标签直接使用。 el表达式的使用 读取javaBean的属性值 方式一:(e1.jsp) ${user.username} "等效:<%= 表达式 %>" 等效代码: User user1=(User)request.getAttribute("user"); out.println(user1.getUsername()); 执行过程:容器依次从pageContext-->request-->session-->application中查找绑定名为 "user"的对象(getAttribute),找到之后调用该对象的"getUsername"方法, 来获取相对应的值,最后输出。 优点: 会将null转换成空字符串""输出。 如果依据绑定名找不到对应的对象,不会报空指针异常。同时转换成""输出。 "属性名不能写错,否则报错" 指定查找范围: 可以使用pageScope requestScope sessionScope applicationScope 来指定查找范围。 "一旦指定查找范围,那么在该范围内没有找到指定的绑定对象,不会再去其他区域中查找" 例子: ${sessionScope.user.username } 方式二: ${user["username"]} //单引号,双引号都可以。属性名不能写错,否则报错。 执行过程和方式一相同; []里面可以出现绑定名 []里面可以出现从0开始的下标,用来访问数组中的某个元素。 <% pageContext.setAttribute("s1", "age"); %> 出现绑定数据名:${user[s1] } Age:${user[requestScope.s1] } <!-- 找不到绑定的数据,打印空字符串 --> Interest:${user.interest[0] } 进行一些简单的运算 算术运算:+ - * / % ${1+1 } 关系运算符: > >= < <= == != <%request.setAttribute("s1", "abc"); %> ${session.Scope.s1 == "abc" } 逻辑运算符:&& || ! ${2>0 && 2<3 } empty运算符:用来判断一个字符串是否为空,或者一个集合是否为空, 以下四种情况为true: 空字符串、空集合、值为null 、找不到对应的值 <% List<String> list=new ArrayList<String>(); request.setAttribute("list", list); %> empty计算:${empty list} <!-- true--> " + 只能求和,不能连接字符串;会把字符串转换成对应的数值进行相加运算" 例如:${"a" + "b"} --> 500 报错 ${"2" + "5"} --> 7 读取请求参数值(e3.jsp) "param"固定用法 ${param.username} //username表示请求参数名 等价于-> request.getParameter("username"); username1: <%=request.getParameter("username") %> username2: ${param.username } "paramValues" ${paramValues.city} 等价于-> request.getParameterValues("city"); <% String[] citys=request.getParameterValues("city"); if(citys !=null){ for(String city:citys){ out.println(city+"<br/>"); } } %> citys:${paramValues.city } //使用jsp标签遍历该数组 citys[0]:${paramValues.city[0] } //使用下标获取指定下标元素

    JSTL(jsp standard tag librariy)标签的引用

    JSTL是什么(jsp standard tag lib): 注: apache开发的一套jsp标签,后来捐献给了sun,sun将其命名为jstl。 jstl如何使用: step1:导包 <dependencies> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> step2:使用taglib指令导入需要使用的jsp标签库 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

    3.JSP标签

    if标签 用法: <c:if test="" var="" scope=""> 标签体 </c:if> b.当test属性值为true时,容器执行标签体的内容。 c.test属性值可以使用el表达式进行计算。 var属性:指定一个绑定名称 scope属性:指定绑定范围(page request session application) "var与scope配合使用" 例子: 性别: <c:if test="${user.gender =='m' }" var="rs" scope="page"></c:if> <c:if test="${!rs}"></c:if> choose标签 用法: <c:choose> <c:when test=""> </c:when> <c:otherwise> </c:otherwise> </c:choose> when可以出一次或者多次,表示一个分支(相当于一个if语句), 当test属性值为true时,执行标签体的内容。test属性值可以使用el表达式来进行计算。 otherwise可以出现0次或者1次,表示例外(相当于最那个else语句) 例子: <c:choose> <c:when test="${user.gender =='m' }"></c:when> <c:when test="${user.gender =='f' }"></c:when> <c:otherwise>保密</c:otherwise> </c:choose> forEach 用法: <c:forEach items="" var="" varStatus=""> </c:forEach> items属性用来指定要遍历的集合或者数据,可以使用el表达式来赋值。 可以使用el表达式,从隐含对象中获取绑定数据。 var属性用来指定绑定名。(绑定范围固定是pageContext,该标签每次从集合或者数组中 取一个元素,然后将其绑定到pageContext上) varStatus属性用来指定绑定名。 绑定范围固定是pageContext,绑订值是一个特殊的对象,该对象由该标签创建, 用来获得当前的遍历状态。 该对象提供了以下方法,用来获得当前遍历的状态: index:返回正在被迭代的下标,下标从0开始 getIndex(): 获得当前正在被遍历的元素的下标(0开始)。 count:返回是第几次迭代,从1开始。 getCount(): 获得当前正在被遍历的元素的序号(1开始)。 例子: <c:forEach items="${users }" var="u" varStatus="s"> <tr class="row${s.index % 2 +1}"> <td>${u.username }</td> <td> <!-- 嵌套choose标签,打印性别 --> <c:choose> <c:when test="${u.gender == 'm'}"></c:when> <c:when test="${u.gender == 'f'}"></c:when> </c:choose> </td> <td>${u.age }</td> <td>${s.index }</td> //index与count两个单词的不能随便改变 <td>${s.count }</td> </tr> </c:forEach>

    自定义JSP标签

    step1.写一个java类,继承SimpleTagSupport类。(简单标签技术) step2.重写doTag方法,在该方方法里面编写处理逻辑。 step3.*.tld文件里面描述该标签。 /** * 标签类的要求: * 1、继承SimpleTagSupport类 * 2、重写doTag方法(实现处理逻辑) * 3、标签有哪些属性,标签类里也必须有对应的属性匹配。 * 属性名称相同,类型匹配,并且有对应的set方法。 * 表标签的执行过程: * 1、容器依据标签的命名空间找到标签的描述文件(.tld文件),然后 * 依据标签名找到标签类,接下来将标签类实例化。 * 2、容器将标签的属性值赋给标签对象,通过调用标签对象set方法, * 如果标签的属性值需要计算,容器会事先计算。 * 3、容器调用标签对象的doTag方法。 */ public class HelloTag extends SimpleTagSupport { private String msg; private int qty; public HelloTag() { System.out.println("HelloTag 构造器运行了!"); } public void setMsg(String msg) { System.out.println("Set msg!"); this.msg = msg; } public void setQty(int qty) { System.out.println("Set qty!"); this.qty = qty; } @Override public void doTag() throws JspException, IOException { System.out.println("Execute doTag method!"); /*通过继承SimpleSupport类的方法来获得pageContext.(页面上下文) * 该对象提供了获得其它所有隐含对象的方法。*/ PageContext pctext=(PageContext)getJspContext(); //强制转换 JspWriter out = pctext.getOut(); //获取out隐含对象 for(int i=0;i<qty;i++){ out.println(msg+"<br/>"); } } 配置 xxx.tld 文件 该文件可以放在WEB-INF文件夹下面 也可以放在jar包的META-INF文件夹下 <?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <description>自定义JSTL标签库</description> <display-name>JSTL core</display-name> <tlib-version>1.0</tlib-version> <short-name>d</short-name> <uri>http://tedu.cn/mytag</uri> <tag> <description>描述你也看不懂</description> <name>hello</name> <tag-class>tag.HelloTag</tag-class> <!-- body-content 用来设置该标签体是否有标签体,如果有,标签体的内容允许出现哪些内容。 值: empty:该标签没有标签体 scriptless:该标签有标签体,该标签体的内容不能任何出现java代码。 JSP:该标签有标签体,并且标签体的内容可以使java代码。 但是只有复杂的标签技术才支持该值。--> <body-content>empty</body-content> <attribute> <description>描述你也看不懂</description> <name>msg</name> <!-- true表示该属性必选 false表示该属性可有可无 --> <required>true</required> <!-- 值为true:表示该属性值可以使用el表达式动态赋值;值为false: 则相反 --> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <name>qty</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib> 使用: <%@ taglib uri="http://tedu.cn/mytag" prefix="d"%> <d:hello msg="Hello Kitty" qty="${2+8}"/> *练习:写一个日期标签,可以按照指定的格式输出日期。 <d:date timeFormat="yyyy-MM-dd"/>

    以上个人对Servlet以及JSP的知识整理,若有遗漏、疑问、或者不懂的地方欢迎留言;别忘了点赞哦!

    Processed: 0.010, SQL: 9