JavaWeb的学习(下)
JavaWeb的学习
尚硅谷JavaWEB基础教程,哔哩哔哩链接:https://www.bilibili.com/video/BV1jW411u7PZ
七、JavaBean
• 用作JavaBean
的类必须具有一个公共的、无参数
的构造方法。
• JavaBean
的属性与普通Java类的属性的概念不一样,JavaBean
的属性是以方法定义的形式出现的。
• 用于对属性赋值的方法称为属性修改器
或setter方法
,用于读取属性值的方法称为属性访问器
或getter方法
。
• 属性修改器必须以小写的set 前缀
开始,后跟属性名,且属性名的第一个字母要改为大写,例如,nickName
属性的修改器名称为setNickName
,password
属性的修改器名称为setPassword
。
• 属性访问器通常以小写的get 前缀开始,后跟属性名,且属性名的第一个字母要改为大写,例如,nickName
属性的访问器名称为getNickName
,password
属性的访问器名称为getPassword
。
• JavaBean
的属性名是根据setter
方法与getter
方法的名称来生成的, setter
方法或getter
方法中除去前缀set
和get
后的部分即为属性名,但属性名的首字母必须小写。
1.在JSP中如何使用JavaBean
• JSP规范专门定义了三个JSP标签:<jsp:useBean>
、<jsp:setProperty>
和<jsp:getPropperty>
,它们分别用于创建和查找JavaBean的实例对象、设置JavaBean对象的属性、读取JavaBean对象的属性
。
• 对于JSP页面来说,只要一个类具有一个公共的、无参数的构造方法,就可以把这个类当作JavaBean
来使用,如果类中有不接受任何参数的getter
方法或只接受一个参数的setter
方法,就可以把前缀get
或set
后面的部分当着一个属性名来引用。
• JSP页面可以像调用一个普通Java
类的方式去调用JavaBean
,即先使用Java
代码创建JavaBean
的实例对象,然后直接调用JavaBean
对象的getter
方法和setter
方法。
<jsp:useBean>
标签
<jsp:setProperty>
标签
<jsp:getProperty>
标签
2.使用JavaBean的注意事项
• JavaBean
应放置在JSP
页面的类装载器或其父级类装载器所能装载的目录中,通常放置于WEB
应用程序下的WEB-INF/classes
目录中。
• 有些版本的Tomcat
不会自动重新加载修改过的JavaBean
,如果JSP
页面加载JavaBean
以后又修改和重新编译了JavaBean
程序,那么需要修改JSP
页面或者重新启动Tomcat
。
• JavaBean必须带有包名,不能用缺省包名。
• 在选择存储JavaBean
的域范围时,如果使用request
域能够满足需求的话,则不要使用Session
域。
3.JavaBean总结
JavaBean常见的组件类型:(1)文件上传组件(FileUpload)(2)验证码组件(3)二维码组件(4)office文件读写组件POI(5)自定义Java组件,如DAO,DTO,VO,Entity等。DAO:持久化对象,用于访问数据。DTO: 数据传输对象,用于封装传输数据模型。VO: 值对象,用于传递参数。Entity:实体对象,用于封装数据库实体模型。JavaBean的特点(可维护、可复用、人员分工分离、跨平台)1.实现了Java代码与HTML代码的分离,便于维护代码,提高了程序的可读性;2.Web应用的业务逻辑由JavaBean实现,这样可以在不同的JSP页面中访问同一个JavaBean,实现代码的复用,从而减少了代码的编写量;3.便于人员分工(前端设计与后台程序设计分离),可以把Web应用的业务逻辑和用户界面设计交由不同的人员开发,降低了开发Web应用人员的整体要求;4.JavaBean具有Java跨平台的特性,可以在任何安装了Java运行环境的平台上的使用,而不需要重新编译。JavaBean开发规范1.JavaBean必须是public类型的公共类;2.JavaBean中需要提供一个public类型的无参构造方法;3.为JavaBean的属性提供setter和getter方法,setter方法为属性设置值,getter方法获取属性的值。假设JavaBean的属性名是xxx,那么该属性的setter和getter方法命名应为setXxx()和getXxx()。对于boolean类型的属性,允许使用“is”代替“get”和“set”;4.getter和setter方法必须是public类型的,而JavaBean的属性必须是private类型;5.设计JavaBean时,通常将其放在一个命名的包下。JavaBean的应用范围1.在JSP中使用<jsp:useBean>、<jsp:setProperty>和<jsp:getProperty>这3个动作标记访问JavaBean。2.其中,<jsp:useBean>动作标记的作用是在JSP页面中产生一个JavaBean的快捷参考(对象变量)。其scope属性有4种取值可能:page(默认)、request、session和application,表示页面所引用JavaBean的应用范围。4.JavaBean的应用分为两种:(1)<jsp:useBean></jsp:useBean>,这种方式页面的JavaBean组件对象实例由JSP页面自动实例化完成。示例:使用JSP动作标记<jsp:useBean id="xxBean" class="xx.xx.xxBean" scope="page"></jsp:useBean>。(2) 使用page标记指令的import属性引入自定义的JavaBean组件,并通过new操作符实例化组件对象,再调用对应方法。这种方式由应用开发者硬编码完成。使用标记指令page+java程序段的方式,格式:<%@ page import="xx.xx.xxBean"%> <% xxBean instance=new xxBean();%>JavaBean的应用范围会话范围(session):指定为会话范围的JavaBean主要应用在跨多个页面和时间段:例如在用户注册中保存用户信息、接受反馈信息、保存用户最近执行页面的轨迹等,这些操作往往是一个用户在不同的JSP页面中操作,并且需要在这些页面之间共享数据。指定为会话范围的JavaBean保留了一些和用户对话 ID 相关的信息。这些信息来自临时的会话Cookie,并在当用户关闭浏览器时,该Cookie将从客户端和服务器删除。页面/请求范围(page/request):页面和请求范围的JavaBean主要用来处理表单。表单需要很长的时间来处理用户的输入,通常情况下用于页面接受HTTP的POST或者GET请求。另外页面/请求范围的JavaBean可以用于减少大型站点服务器上的负载,如果使用会话范围的JavaBean,耽搁的处理可能会消耗掉很多系统资源。应用范围(application):应用范围通常应用于服务器的部件,例如JDBC连接池、应用监视、用户计数和其他参与用户行为的类。
八、自定义标签
提出问题
• 自定义标签可以降低jsp
开发的复杂度和维护量,从 html 角度来说,可以使 html 不用去过多的关注那些比较复杂的商业逻辑(业务逻辑)。
• 利用自定义标签,可以软件开发人员和页面设计人员合理分工:页面设计人员可以把精力集中在使用标签(HTML,XML或者JSP)创建网站上,而软件开发人员则可以将精力集中在实现底层功能上面,如国际化等,从而提高了工程生产力
• 将具有共用特性的tag库
应用于不同的项目中,体现了软件复用的思想。
1.什么是自定义标签
• 用户定义的一种自定义的jsp标记
。当一个含有自定义标签的jsp
页面被jsp引擎
编译成servle
t时,tag标签
被转化成了对一个称为 标签处理类
的对象的操作。于是,当jsp页面被jsp引擎转化为servlet后,实际上tag标签
被转化为了对tag处理类
的操作。
2.标签库 API
• 标签库 API 定义在 javax.servlet.jsp.tagext
包中
3.传统标签和简单标签
• 开发自定义标签,其核心就是要编写处理器类,一个标签对应一个标签处理器类
,而一个标签库则是很多标签处理器的集合。所有的标签处理器类都要实现 JspTag
接口,该接口中没有定义任何方法,主要作为 Tag
和 SimpleTag
接口的父接口。
• 在JSP 2.0
以前,所有标签处理器类都必须实现 Tag
接口,这样的标签称为传统标签
。
• JSP 2.0
规范又定义了一种新的类型的标签,称为简单标签
,其对应的处理器类要实现 SimpleTag
接口
标签的形式
•空标签:<hello/>•带有属性的空标签:<max num1="3" num2="5"/>•带有内容的标签:<greeting>hello</greeting>•带有内容和属性的标签:<greeting name="Tom">hello</greeting>
自定义标签的开发与应用步骤
• 编写完成标签功能的Java
类(标签处理器)
• 编写标签库描述(tld
)文件,在tld
文件中对自定义中进行描述
• 在JSP
页面中导入和使用自定义标签
SimpleTag 接口
• setJspContext
方法:该方法把代表 JSP 页面的 pageContext
对象传递给标签处理器对象。
• setParent
方法:该方法把父标签处理器对象传递给当前标签处理器对象
• getParent
方法:该方法用于获得标签的父标签处理器对象
• setJspBody
方法:该方法用于把代表标签体的 JspFragment
对象传递给标签处理器对象
• doTag
方法:该方法用于完成所有的标签逻辑。该方法可以抛出javax.servlet.jsp.SkipPageException
异常,用于通知 web 容器不再执行 JSP 页面中位于结束标记后面的内容。
实现 SimpleTag 接口的标签处理器类的生命周期
JspFragment 类
• 该类的实例对象代表 JSP 页面中的一段符合 JSP 语法规范的 JSP 片段,这段 JSP 片段不能包含 JSP 脚本元素(<% … %>
)
• JSP 引擎在处理简单标签的标签体时,会把标签体内容用一个 JspFragment
对象表示,并调用标签处理器对象的 setJspBody
方法把 JspFragment
对象传递给标签处理器对象。得到代表标签体的JspFragment
对象后,标签开发者和就可以在标签处理器中根据需要调用 JspFragment
对象的方法,进而决定如何处理标签体。
• getJspContext
方法:该方法用于返回代表调用页面的 JspContext
对象
• Invoke
方法(java.io.Writer out
):该方法用于执行 JspFragment
对象所代表的 JSP 代码片段。在 doTag()
方法中可以根据需要调用该方法。
—该方法的参数 out 用于指定将 JspFragment 对象的执行结果写入到哪个输出流对象中。若传递参数 out 的值为 null,则将执行结果写入到 JspContext.geOut() 方法返回的输出流对象中。
— 若想在标签处理器中修改标签体内容:需在调用 invoke 方法时指定一个可取出结果数据的输出流对象(如:StringWriter),让标签体的执行结果输出到该输出流中,然后从该输出流对象中取出数据进行修改后在输出到目标设备
SimpleTagSupport
•为简化简单标签处理器的编写工作,JSP API 中提供了SimpleTag
接口的一个实现类SimpleTagSupport
。
•SimpleTagSupport
实现了SimpleTag
接口中的方法,它内部以成员变量的形式保存了setJspContext
方法和setJspBody
方法传递进来的参数。此外,它还定义了如下两个方法、来返回这两个参数:
– getJspContext
方法:该方法用于返回代表调用页面的JspContext
对象
– getJspBody
方法:该方法用于得到代表标签体的JspFragment
对象
标签库描述文件
• 标签库描述(Tag Library Description
)文件简称为tld
文件,其扩展名为.tld
• 多个标签的集合就形成了一个标签库,标签库中的所有标签都必须在标签文件中进行描述
• Tld
文件可以放置在 web
应用程序的 WEB-INF
目录及其子目录中,但不能放置在 WEB-INF
目录下的 classes
和 lib
子目录中 。tld
文件也可以放置在 WEB-INF\lib
目录下的jar
包的META-INF
目录及其子目录中
•<body-content>
:指定标签体的类型。可能取值有3
种:
– empty
:没有标签体
– scriptless
:标签体可以包含el
表达式和 JSP
动作元素,但不能包含 JSP 的脚本元素
– tagdependent
:表示标签体交由标签本身去解析处理。若指定tagdependent
,在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器
在 JSP 页面引用自定义标签
• 在 JSP
页面使用taglib
指令引入标签库描述文件:
<%@ taglib prefix=“” uri=“” %>
• uri
:属性用于指定所引入的标签库描述(tld
)文件中所定义的<uri>
元素的内容;prefix
属性用于为引入的tld
文件指定一个”引用代号”。Prefix
属性可以由jsp
文件的作者任意指定,只要与其他taglib
指令的 prefix
属性值不同就可以。
4.EL 自定义函数
• EL 自定义函数
:在 EL
表达式中调用的某个 Java 类的静态方法,这个静态方法需在 web 应用程序中进行配置才可以被 EL 表达式
调用。
• EL
自定义函数可以扩展 EL 表达式的功能,让 EL 表达式完成普通 Java 程序代码所能完成的功能。
EL 自定义函数开发步骤
• 编写 EL 自定义函数映射的Java 类中的静态方法:
这个 Java 类必须带有 public
修饰符,方法必须是这个类的带有 public 修饰符的静态方法
• 编写标签库描述文件(tld
文件), 在tld
文件中描述自定义函数
• 在 JSP 页面中导入和使用自定义函数
在 tld 文件中描述 EL 自定义函数
• 为了能够让一个 Java 类的静态方法可以被 EL 表达式
调用,需要在一个标签库描述文件(tld
文件)中对 EL 自定义函数进行描述,以将 Java 类中的静态方法映射成一个 EL 自定义函数
在 JSP 页面中导入和使用 EL 自定义函数
• 在标准 JSP 页面中使用 taglib
指令来引入 tld
文件:
<%@ taglib uri="/petrelskyTag" prefix="petrelsky"%>
• uri
:属性用于指定所引入的标签库描述(tld
)文件中所定义的 <uri>
元素的内容;prefix
属性用于为引入的 tld
文件指定一个”引用代号”。Prefix
属性可以由jsp
文件的作者任意指定,只要与其他taglib
指令的 prefix
属性值不同就可以。
• 调用 EL 自定义函数:
${petrelsky :toGBK (param.username) }
jstl fn 函数
• 为了简化在 JSP 页面操作字符串,JSTL 中提供了一套 EL 自定义函数,这些自定义函数包含了 JSP 页面制经常要用到的字符串操作
• 在JSTL的表达是中要使用一个函数,其格式如下
${ns:methodName(args....)}
• 在使用这些函数之前必须在JSP中引入标准函数的声明
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
九、过滤器(Filter)
1.Filter(过滤器)简介
• Filter 的基本功能是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊的功能。
• 在 Servlet API 中定义了三个接口类来开供开发人员编写 Filter 程序:Filter, FilterChain, FilterConfig
• Filter 程序是一个实现了 Filter 接口的 Java 类,与 Servlet 程序相似,它由 Servlet 容器进行调用和执行
• Filter 程序需要在 web.xml 文件中进行注册和设置它所能拦截的资源:Filter 程序可以拦截 Jsp, Servlet, 静态图片文件和静态 html 文件
2.Filter 的过滤过程
3.Filter 的基本工作原理
• 当在 web.xml
中注册了一个Filter
来对某个 Servlet 程序进行拦截处理时,这个 Filter 就成了 Servlet 容器与该 Servlet 程序的通信线路上的一道关卡,该 Filter 可以对 Servlet 容器发送给 Servlet 程序的请求和 Servlet 程序回送给 Servlet 容器的相应进行拦截,可以决定是否将请求继续传递给 Servlet 程序,以及对请求和相应信息是否进行修改
• 在一个 web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序都可以对一个或一组
Servlet 程序进行拦截。
• 若有多个 Filter 程序对某个 Servlet 程序的访问过程进行拦截,当针对该 Servlet 的访问请求到达时,web 容器将把这多个 Filter 程序组合成一个 Filter 链(过滤器链)。Filter 链中各个 Filter 的拦截顺序与它们在应用程序的 web.xml 中映射的顺序一致
4.Filter 接口
• init(FilterConfig filterConfig)throws ServletException:在 web 应用程序启动时,web 服务器将根据 web.xml
文件中的配置信息来创建每个注册的Filter
实例对象,并将其保存在服务器的内存中。
• Web容器创建 Filter 对象实例后,将立即调用该 Filter 对象的 init 方法。Init 方法在 Filter 生命周期中仅执行一次,web 容器在调用init
方法时,会传递一个包含Filter
的配置和运行环境的 FilterConfig
对象(FilterConfig
的用法和ServletConfig
类似)。
• 利用FilterConfig
对象可以得到ServletContext
对象,以及部署描述符中配置的过滤器的初始化参数。在这个方法中,可以抛出ServletException
异常,通知容器该过滤器不能正常工作。
• destroy():在Web容器卸载 Filter 对象之前被调用。该方法在Filter
的生命周期中仅执行一次
。在这个方法中,可以释放过滤器使用的资源
• 与开发Servlet不同的是,Filter
接口并没有相应的实现类可供继承,要开发过滤器,只能直接实现Filter接口
。
• doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throws java.io.IOException,ServletException:
doFilter()
方法类似于Servlet接口的service()
方法。
当客户端请求目标资源的时候,容器就会调用与这个目标资源相关联的过滤器的doFilter()
方法。其中参数 request, response
为 web 容器或 Filter 链的上一个 Filter
传递过来的请求和相应对象;
参数 chain
为代表当前 Filter 链
的对象,在特定的操作完成后,可以在当前Filter
对象的 doFilter
方法内部需要调用 FilterChain
对象的 chain.doFilter(request,response)
方法才能把请求交付给 Filter 链
中的下一个 Filter
或者目标 Servlet 程序
去处理,也可以直接向客户端返回响应信息,或者利用RequestDispatcher
的forward()
和include()
方法,以及HttpServletResponse
的sendRedirect()
方法将请求转向到其他资源。这个方法的请求和响应参数的类型是ServletRequest
和ServletResponse
,也就是说,过滤器的使用并不依赖于具体的协议。
5.FilterChain接口
• FilterChain
接口:代表当前 Filter 链的对象。由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()
方法中。过滤器对象使用FilterChain
对象调用过滤器链中的下一个过滤器,如果该过滤器是链中最后一个过滤器,那么将调用目标资源。
• doFilter(ServletRequest request,ServletResponse response)throws java.io.IOException
:调用该方法将使过滤器链中的下一个过滤器被调用。如果是最后一个过滤器,会调用目标资源。
6.FilterConfig 接口
• javax.servlet.FilterConfig
接口:该接口类似于ServletConfig
接口,由容器实现。Servlet规范将代表ServletContext
对象和Filter
的配置参数信息都封装在该对象中。Servlet 容器将其作为参数传入过滤器对象的init()
方法中。
• String getFilterName()
:得到描述符中指定的过滤器的名字。
• String getInitParameter(String name)
: 返回在部署描述中指定的名字为name的初始化参数的值。如果不存在返回null.
• Enumeration getInitParameterNames()
:返回过滤器的所有初始化参数的名字的枚举集合。
• public ServletContext getServletContext()
:返回Servlet上下文对象的引用。
7.过滤器的部署
• 在实现一个过滤器后,需要在web.xml
中进行注册和设置它所能拦截的资源。这可以通过<filter>
和<filter-mapping>
元素来完成。
8.filter 元素(注册Filter)
• <filter>
元素用于在Web应用程序中注册一个过滤器。
• 在<filter>
元素内
–<filter-name>
用于为过滤器指定一个名字,该元素的内容不能为空。
–<filter-class>
元素用于指定过滤器的完整的限定类名。
–<init-param>
元素用于为过滤器指定初始化参数,它的子元素<param-name>
指定参数的名字,<param-value>
指定参数的值。在过滤器中,可以使用FilterConfig
接口对象来访问初始化参数。
• Servlet容器对部署描述符中声明的每一个过滤器,只创建一个实例。与Servlet类似,容器将在同一个过滤器实例上运行多个线程来同时为多个请求服务,因此,开发过滤器时,也要注意线程安全
的问题。
<filter><filter-name>testFitler</filter-name><filter-class>org.test.TestFiter</filter-class><init-param><param-name>word_file</param-name> <param-value>/WEB-INF/word.txt</param-value></init-param>
</filter>
9.映射 Filter
• <filter-mapping>
元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称
和资源访问的请求路径( url样式)
–<filter-name>
子元素用于设置filter的注册名称。该值必须是在<filter>
元素中声明过的过滤器的名字
–<url-pattern>
设置 filter 所拦截的请求路径(过滤器关联的URL样式)
–<servlet-name>
指定过滤器所拦截的Servlet名称。
–<dispatcher>
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR
之一,默认REQUEST
。可以设置多个子元素用来指定 Filter对资源的多种调用方式进行拦截
• <dispatcher>
子元素可以设置的值及其意义:
– REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher
的include()
或forward()
方法访问时,那么该过滤器就不会被调用。
– INCLUDE:如果目标资源是通过RequestDispatcher
的include()
方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
– FORWARD:如果目标资源是通过RequestDispatcher
的forward()
方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
– ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
<filter-mapping><filter-name>testFilter</filter-name><url-pattern>/test.jsp</url-pattern>
</filter-mapping>
<filter-mapping><filter-name>testFilter</filter-name><url-pattern>/index.jsp</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher>
</filter-mapping>
• 在同一个web.xml
文件中可以为同一个 Filter 设置多个映射。若一个 Filter 链中多次出现了同一个 Filter 程序,这个 Filter 程序的拦截处理过程将被多次执行
典型应用1
• 使浏览器不缓存页面的过滤器:
– 有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:
• response.setDateHeader("Expires",-1);
• response.setHeader("Cache-Control","no-cache");
• response.setHeader("Pragma","no-cache");
– 并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用
上面的三个响应头
典型应用2
• 字符编码的过滤器
–通过配置参数encoding
指明使用何种字符编码,以处理Html Form
请求参数的中文问题
典型应用3
• 检测用户是否登陆的过滤器:
–情景:系统中的某些页面只有在正常登陆后才可以使用,用户请求这些页面时要检查 session
中有无该用户信息,但在所有必要的页面加上session
的判断相当麻烦的事情
–解决方案:编写一个用于检测用户是否登陆的过滤器,如果用户未登录,则重定向到指的登录页面
–要求:需检查的在 Session
中保存的关键字; 如果用户未登录,需重定向到指定的页面(URL不包括 ContextPath
); 不做检查的URL列表(以分号分开,并且 URL 中不包括ContextPath
)都要采取可配置的方式
典型应用4
10.装饰 HttpServletRequest 对象
• 需求:在HttpServletRequest
对象到达 Servlet 之前把用户输入的多余空格都去掉
• 情景:因为 HttpServletRequest
对象里的请求参数都实际包含在 java.util.Map
对象里,而Map
是不允许修改的,所以包含在 HttpServletRequest
对象里的请求参数不能被修改
• 解决方案:采取 Decorator(装饰器)模式
Decorator 模式
• 因为继承的关系,当需要改变某个对象的行为时,只须扩展这个对象所属的类并重写其有关的方法就可以达到目的。但是,当想要改变其行为的对象是由应用程序里的另一个子系统(例如:一个对象工厂或是一个Servlet容器)负责构造,继承机制将无能为力
Decorator 模式----情景
• 已知:Messager 类的定义(可以从它派生处一个之类);Messager 对象总是来自一个对象工厂(MessagerFactory),该工厂可以对它创建的每一个 Messager 对象进行初始化----通过调用 getMessage() 方法而获得的 message 属性也不例外(即不能对 Messager 对象进行初始化)
• 假设:需要使用 Messager 类的 getMessage() 方法。有一个Util的使用工具类,该类中有如下方法:
public static void broadcast(Message messager){System.out.println(messager.getMessage());
}
Decorator 模式----需求,方案
• 需求:让 broadcast 方法打印的字母都是大写字母
• 方案:从 Messager 类派生一个子类,把子类对象传递给 broadcast 方法。因为只有对象工厂知道如何初始化 Messager 对象,所以该方案无意义
• Decorator 模式:
–从 Messager 类派生一个子类 MessagerDecorator,把子类对象传递给 broadcast 方法
–在 MessagerDecorator 类里实现构造器:接受一个 Messager 对象作为输入参数,而这个 Messager 就是想要装饰的对象:public MessagerDecorator(Messager messager)
–重写 getMessage 方法,让重写的方法用大写字母来返回 message 属性
11.HttpServletRequestWrapper类
• Servlet API
中提供了一个 HttpServletRequestWrapper
类来包装原始的 request
对象,HttpServletRequestWrapper
类实现了 HttpServletRequest
接口中的所有方法,这些方法的内部实现都是仅仅调用了一下所包装的的 request
对象的对应方法
• 相类似Servlet API
也提供了一个 HttpServletResponseWrapper
类来包装原始的 response
对象
典型应用5:为论坛过滤不雅文字和HTML特殊字符
• 开发论坛模块时要解决以下两个问题:
–1. 用户回复或发帖时可能会输入 HTML 代码(例如:<, >等),这可能会破坏论坛的正常显示,也可能会带来安全隐患。
–2. 某些用户在回复时可能会输入不雅子句,这些子句会给论坛带来不好的影响
–3. 实现对不雅文字的可配置
• 要求:不雅文字及其替换内容实现可配置。
十、监听器
• 监听器:专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。
• Servlet 监听器
:Servlet 规范中定义的一种特殊类,它用于监听 web 应用程序中的 ServletContext, HttpSession 和 ServletRequest 等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
Servlet 监听器的分类
• 按监听的事件类型 Servlet 监听器可分为如下三种类型:
–监听域对象自身的创建和销毁的事件监听器
–监听域对象中的属性的增加和删除的事件监听器
–监听绑定到 HttpSession
域中的某个对象的状态的事件监听器
1.编写 Servlet 监听器
• Servlet 规范为每种事件监听器都定义了相应的接口,开发人员编写的事件监听器程序只需实现这些接口,web 服务器根据用户编写的事件监听器所实现的接口把它注册到相应的被监听对象上
• 一些 Servlet 事件监听器需要在 web 应用程序的 web.xml
文件中进行注册,一个 web.xml 文件中可以注册多个 Servlet事件监听器,web 服务器按照它们在 web.xml
文件中的注册顺序来加载和注册这些 Serlvet 事件监听器。
• Serlvet 事件监听器的注册和调用过程都是由 web 容器自动完成的,当发生被监听的对象被创建,修改或销毁事件时,web容器将调用与之相关的 Servlet 事件监听器对象的相关方法,开发人员在在这些方法中编写的事件处理代码即被执行
• 由于一个 web 应用程序只会为每个事件监听器创建一个对象,有可能出现多个线程同时调用同一个事件监听器对象的情况,所以,在编写事件监听器类时,应考虑多线程安全
的问题
2.监听域对象的创建和销毁
• 域对象创建和销毁的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest
这三个对象的创建和销毁事件的监听器。
• 域对象的创建和销毁时机
ServletContextListener 接口
• ServletContextListener 接口用于监听 ServletContext
对象的创建和销毁事件。
• 当 ServletContext
对象被创建时,激发contextInitialized (ServletContextEvent sce)
方法
• 当 ServletContext
对象被销毁时,激发contextDestroyed(ServletContextEvent sce)
方法
HttpSessionListener 接口
• HttpSessionListener
接口用于监听HttpSession
对象的创建和销毁
• 创建一个Session
时,激发sessionCreated(HttpSessionEvent se)
方法
• 销毁一个Session
时,激发sessionDestroyed (HttpSessionEvent se)
方法。
ServletRequestListener接口
• ServletRequestListener
接口用于监听ServletRequest
对象的创建和销毁
• 创建一个ServletRequest
对象时,激发requestInitialized(ServletRequestEvent sre)
方法
• 销毁一个Session
时,激发requestDestroyed(ServletRequestEvent sre)
方法。
3.域对象中属性的变更的事件监听器
• 域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest
这三个对象中的属性变更信息事件的监听器。
• 这三个监听器接口分别是ServletContextAttributeListener, HttpSessionAttributeListener 和ServletRequestAttributeListener
,这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同
4.attributeAdded 方法
• 当向被监听器对象中增加一个属性时,web容器就调用事件监听器的attributeAdded
方法进行相应,这个方法接受一个事件类型的参数,监听器可以通过这个参数来获得正在增加属性的域对象和被保存到域中的属性对象
• 各个域属性监听器中的完整语法定义为:
–public void attributeAdded(ServletContextAttributeEvent scae)
–public void attributeReplaced(HttpSessionBindingEvent hsbe)
–public void attributeRmoved(ServletRequestAttributeEvent srae)
5.attributeRemoved 方法
• 当删除被监听对象中的一个属性时,web 容器调用事件监听器的这个方法进行相应
• 各个域属性监听器中的完整语法定义为:
–public void attributeRemoved(ServletContextAttributeEvent scae)
–public void attributeRemoved (HttpSessionBindingEvent hsbe)
–public void attributeRemoved (ServletRequestAttributeEvent srae)
6.attributeReplaced 方法
• 当监听器的域对象中的某个属性被替换时,web容器调用事件监听器的这个方法进行相应
• 各个域属性监听器中的完整语法定义为:
–public void attributeReplaced(ServletContextAttributeEventscae)
–public void attributeReplaced (HttpSessionBindingEventhsbe)
–public void attributeReplaced (ServletRequestAttributeEventsrae)
7.感知 Session 绑定的事件监听器
• 保存在 Session
域中的对象可以有多种状态:绑定到 Session 中;从 Session 域中解除绑定;随 Session 对象持久化到一个存储设备中;随 Session 对象从一个存储设备中恢复
• Servlet 规范中定义了两个特殊的监听器接口来帮助 JavaBean 对象了解自己在 Session 域中的这些状态HttpSessionBindingListener
接口和HttpSessionActivationListener
接口 ,实现这两个接口的类不需要 web.xml 文件中进行注册
8.HttpSessionBindingListener接口
• 实现了HttpSessionBindingListener
接口的 JavaBean 对象可以感知自己被绑定到 Session 中和从 Session 中删除的事件
• 当对象被绑定到 HttpSession 对象中时,web 服务器调用该对象的 void valueBound(HttpSessionBindingEvent event)
方法
• 当对象从 HttpSession 对象中解除绑定时,web 服务器调用该对象的 void valueUnbound(HttpSessionBindingEvent event)
方法
9.HttpSessionActivationListener接口
• 实现了HttpSessionBindingListener
接口的JavaBean
对象可以感知自己被活化和钝化的事件
• 当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被钝化之前,web 服务器调用该对象的 void sessionWillPassivate(HttpSessionBindingEvent event)
方法
• 当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被活化之后,web 服务器调用该对象的 void sessionDidActive(HttpSessionBindingEvent event)
方法
十一、文件的上传下载
1.基于表单的文件上传
如果在表单中使用表单元素 <input type="file" />
,浏览器在解析表单时,会自动生成一个输入框和一个按钮,输入框可供用户填写本地文件的文件名和路径名,按钮可以让浏览器打开一个文件选择框供用户选择文件:
2.Enctype 属性
• 当表单需要上传文件时,需指定表单 enctype 的值为 multipart/form-data
• 在 form 元素的语法中,enctype
属性指定将数据发送到服务器时浏览器使用的编码类型。
• enctype 属性取值:
–application/x-www-form-urlencoded
:表单 enctype 属性的默认值。这种编码方案使用有限的字符集,当使用了非字母和数字时,必须用%HH
代替(H
代表十六进制数字)。对于大容量的二进制数据或包含非 ASCII 字符的文本来说,这种编码不能满足要求。
–multipart/form-data
:form 设定了enctype=“multipart/form-data
属性后,表示表单以二进制传输数据
3.Commons-fileupload组件
• Commons-fileupload
组件是 Apache 开源代码组织用来处理表单文件上传的一个子项目,该组件性能优异,可以支持任意大小的文件的上传
• Commons-fileupload
组件从 1.1 版本开始依赖 Apache 的另一个项目:commons-io
Commons-fileupload组件上传的基本原理
• FileUpload
组件将页面提交的所有元素(普通form表单域,如text和文件域file
)都看作一样的FileItem
,这样上传页面提交的 request
请求也就是一个FileItem
的有序组合,
• FileUpload
组件可以解析该request
,并返回一个一个的FileItem
。而对每一个FileItem
,FileUpload
组件可以判断出它是普通form表单域还是文件file域,从而根据不同的类型,采取不同的操作--如果是表单域,就读出其值,如果是文件域,就保存文件到服务器硬盘上或者内存中。
Commons-fileupload组件API
• 在 Commons-fileupload
组件中,主要用到以下三个接口和类:
• ServletFileUpload
负责处理上传的文件数据,并将每部分的数据封装成一到 FileItem
对象中。
• DiskFileItemFactory
是创建 FileItem
对象的工厂,在这个工厂类中可以配置内存缓冲区大小和存放临时文件的目录。
• ServletFileUpload
在接收上传文件数据时,会将内容保存到内存缓存区中,如果文件内容超过了 DiskFileItemFactory
指定的缓冲区的大小,那么文件将被保存到磁盘上,存储为 DiskFileItemFactory
指定目录中的临时文件。等文件数据都接收完毕后,ServletUpload
在从文件中将数据写入到上传文件目录下的文件中
4.文件的下载
• 情景:在一些网络系统中,需要隐藏下载文件的真实地址,或者下载的文件需要一个程序来动态的确定后在传送给客户端
• 方案:利用程序编码
实现下载
–可以增加安全访问控制,只对经过授权认证的用户提供下载
–可以从任意位置提供下载的数据
• 因为要下载的文件可以是各种类型的文件,所以要将文件传送给客户端,其相应内容应该被当做二进制来处理,所以应该调用response.getOutputStream()
方法返回 ServeltOutputStream
对象来向客户端写入文件内容。
十二、国际化
1.概述
- 软件的本地化:一个软件在某个国家或地区使用时,采用该国家或地区的语言,数字,货币,日期等习惯。
- 软件的国际化:软件开发时,让它能支持多个国家和地区的本地化应用。使得应用软件能够适应多个地区的语言和文化风俗习惯。
- 随用户区域信息而变化的数据称为本地信息敏感数据。例如数字,货币等数据。
- 应用程序的国际化就是在应用软件的设计阶段,使软件能够支持多个国家和地区的用户的使用习惯。
- 国际化又称为 i18n:
internationalization
2.软件国际化的特征
一个国际化的应用软件应有下面的特性:
- 对于程序中的本地信息敏感的数据(
日期,货币等
)能根据当前所在的国家或地区的文化习惯进行显示 - 对于文本元素(
错误提示信息,状态信息等
)不是直接写在应用程序中,而是存储在应用程序外部的资源文件中,在应用程序中通过程序代码来动态获得这些数据 - 无需修改和重新编译程序就能支持新的国家或地区的用户使用
3.Java 国际化解决方案
• 本文信息不能硬编码在程序代码中,而是需要将它们从应用程序中分离出来,在软件运行时根据本地信息读取相应的文本内容进行显示
• 数值,货币,时间,日期等本地敏感数据可能在程序运行时动态产生,所以无法像文字一样简单地将它们从应用程序中分离出来,而是需要特殊处理。Java 中提供了解决这些问题的 API 类(位于java.util
包和java.text
包中)
4.Locale 类
• Locale
实例对象代表一个特定的地理,政治或文化上的区域
• 一个 Locale 对象本身不会验证它代表的语言和国家地区信息是否正确,只是向本地敏感的类提供本地信息,与国际化相关的格式化和解析任务由本地敏感的类(若JDK中的某个类在运行时需要根据 Locale 对象来调整其功能,这个类就称为本地敏感类)去完成
5.DateFormat 类
• DateFormat
类可以将一个日期/时间对象格式化为表示某个国家地区的日期/时间字符串**,**也可以将表示某个本地的日期/时间的字符串解析为相应的日期/时间对象
• DateFormat
类定义了一些用于描述日期/时间的显示模式的int
型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT
,这些常量用于描述表示日期/时间字符串的长度。这些常量说明表示的日期/时间的确切格式取决于具体的国家和地区
• 获取 DateFormat
对象
• DateFormat
对象通常不是线程安全的,每个线程都应该创建自己的 DateFormat 实例对象
• DateFormat
对象的方法:
–format
: 将日期/时间对象格式化为符合某个本地环境习惯的字符串
–parse
:将符合某个本地环境习惯的日期/时间字符串解析为日期/时间对象
6.NumberFormat 类
• NumberFormat 可以将一个数值格式化为符合某个国家地区习惯的数值字符串,也可以将符合某个国家地区习惯的数值字符串解析为对应的数值
• NumberFormat
类的方法:
–format
方法:将一个数值格式化为符合某个国家地区习惯的数值字符串
–parse
方法:符合某个国家地区习惯的数值字符串解析为对应的数值
7.MessageFormat 类
• MessageFormat 类提供了一种参数替换模式字符串中的占位符的方式,它将根据模式字符串中包含的占位符产生一系列的格式化对象,然会调用这些格式化对象对参数进行格式化,并用格式化后的结果字符串替换模式字符串中的相应占位符。
8.模式字符串与占位符
9.MessageFormat 格式化模式字符串
• MessageFormat 类可以格式化模式字符串,它根据其中的占位符产生一系列的格式化对象,然后调用这些格式化对象对参数进行格式化,并用格式化后的结果字符串替换模式字符串中的相应占位符。
• 格式化模式字符串的步骤:
–创建 MessageFormat 对象:须指定格式化的模式字符串,也可以指定 Locale 对象来按某个国家地区的习惯进行格式化。
–调用 MessageFormat 对象的 format 方法执行格式化操作:须为format 方法传递一个数组类型的参数,数组中的每个元素分别用于代替模式字符串中的与其索引号相对应的占位符
10.ResourceBundle 类
• ResourceBundle 类用于描述一个资源包**,一个资源包用于包含一组与某个本地环境相关的对象,可以从一个资源包中获取特定于本地环境的对象。对于不同的本地环境,可以有不同的 **ResourceBundle对象与之关联,关联的 ResourceBundle 对象中包含该本地环境下专有的对象
11.资源包简介
• 在设计一个国际化应用时,应该把程序显示的文本内容从源程序中分离出来,放在独立的资源文件中,并针对不同的本地环境编写不同的资源文件。这些资源文件被称为应用程序的资源包
• 应用程序在运行时,将从与用户的本地环境相对应资源文件中读取名称项对应的值的内容,由于同一个名称项在各个资源文件中对应的值内容是随本地环境信息而改变的,这样就实现了程序的静态文本内容的国际化。
• 当要为应用程序添加某个新的本地化支持时,只需编写一个适合的本地环境的资源文件即可,不用修改源程序代码
• 一个应用程序可以有多个资源包,一个资源包中的每个资源文件都拥有共同的基名。除了基名,每个资源文件的名称中还有标识其本地信息的附加部分。例如:一个资源包的基名是:myproperties
, 则该资源包中与中文环境相对应的资源文件为: myproperites_zh.properties
• 一般情况下,每个资源包都有一个默认的资源文件,默认的资源文件不带标识本地信息的附加部分。若应用程序在资源包中找不到某个本地环境匹配的资源文件,最后将选择该资源包中的默认资源文件。
12.资源文件的内部格式
• 资源文件通常采用java.util.Properties
类要求的文件格式,其中包含每项资源信息的名称项和值内容,每个名称项用于唯一地标识一个资源信息,值内容用于指定资源信息在某个本地环境下的内容
• 一个资源包中的所有资源文件中通常都应包含相同的名称项,与各个本地环境对应的资源文件中为这些名称项设置的值分别是适合该本地环境的内容。
• 资源文件完全遵循 java.util.Properties
类要求的文件格式,它要求资源文件中的字符必须全部为有效的 ASCII 字符。若资源文件中要包含非 ASCII 的字符,必须将它们转化成\uXXXX
形式的转移序列,其中 XXXX 是该字符的 Unicode 编码的十六进制数值
13.使用 native2ascii 程序转换字符编码
• JDK 中提供了一个 native2ascii 工具程序,它可以将某种本地字符集编码的字符转换成 Unicode 转义序列的形式
• DOS 下进入 haha.txt 文件所在目录,运行下面的命令后将在当前目录下生成一个名为 hehe.properites 文件:
native2ascii -encoding gb2312 haha.txt haha.properites
14.装载资源包
• ResourceBundle
类提供了存放和管理资源包的功能
• 当应用程序需要获取特定locale
对象关联的资源包时,可以调用ResourceBundle
的getBundle
方法,并将locale
对象作为参数传入。
Locale currentLocale = Locale.getDefault();ResourceBundle myResources = ResourceBundle.getBundle(“myproperties ", currentLocale);
• 如果与该locale对象匹配的资源包子类找不到,getBundle将试着查找最匹配的一个子类。如果特定locale对象的语言代码、国家代码和可选变量都是空值,则基名是唯一的候选资源包名称。
15.读取资源信息
• 加载资源文件后, ResourceBundle 的实例对象就可以使用 getString 方法获取指定的资源信息名称所对应的值。
String OkKey = myResources.getString("OkKey");
16.Web 应用程序的国际化
• 实现 web 应用国际化有两种方式:
– 针对不同语言和地区的用户开发出不同的 JSP 网页版本,当用户请求资源时,根据请求消息中携带的本地信息为用户提供合适的版本
– 将对本地环境敏感的资源数据(例如:错误提示信息,菜单文字等)从网页中分离出来,放在.properties
属性资源文件中。对于应用程序中的数值,货币和日期/时间等本地敏感数据,可以通过占位符的方式设置它们的格式类型和格式模式。
17.获取 web 应用中的本地信息
• 要实现 web 应用的国际化,首先要获得客户端浏览器的本地信息。
• 在 Servlet 程序中,调用 HttpServletRequest
对象的 方法获得代表客户端本地信息的 Locale 对象:
– getLocale()
:返回代表客户端的首选本地信息的 Locale 对象
– getLocales()
:返回一个包含客户端支持的所有本地信息的 Locale
对象的 Enumeration
对象,这些Locale 对象按照客户端支持的所有本地信息的优先级在集合中一次排列
18.国际化格式标签库示例(1)
19.国际化格式标签库示例(2)
20.国际化格式标签库简介
•<fmt:formatNumber>标签用于根据设定的区域将数据格式化输出;•<fmt:formatDate>标签用于格式化输出日期和时间;•<fmt:parseDate>标签用于把字符串类型的日期和时间转换成日期型数据类型;•<fmt:setTimeZone>标签用于设定默认的时区;•<fmt:timeZone>标签用于设定在本签体内有效的时区
十三、扩展
使用Ideal创建并运行第一个JavaWeb项目
可以查看我的博客,点击前往
框架
框架是一个半成品,已经对基础的代码进行了封装并提供相应的API,开发者在使用框架是直接调用封装好的api可以省去很多代码编写,从而提高工作效率和开发速度。
框架是一种经过校验、具有一定功能的半成品软件
经过校验:
指框架本身经过测试,且框架自身所具有的功能已经实现
具有一定功能:
指框架可以完成特定的功能,不同的框架功能不同
半成品软件:
指框架自身是一个软件,但是该软件无法直接运行,需要配合其他的程序才可以完成指定的工作
框架的工作模式:
开发工程师建立在框架的基础之上完成开发者完成部分加框架自身完成部分组成一个完整的产品
1.什么是框架?
其实框架,就是别人写好了包装起来的一套工具,把你原先必须要写的,必须要做的一些复杂的东西都写好了放在那里,你只要调用他的方法,就可以实现一些本来要费好大劲的功能。
形象一点说吧,假如你盖房子,你是自己一砖一瓦的盖简单呢,还是拿一个现成的架子往上面添东西简单呢?结果不言而喻吧,有一个半成品的架子,你只需要添上一些你自己额外需要加的东西就好了。这就是框架的好处。
假如,好多好多地方都要用这么一套逻辑,那么我们会定义成一个方法(函数),就免去了写同样代码的麻烦,其实这个方法,就是一个框架啦,只不过非常小而已。
web开发的MVC模式,M是模型,V是视图(表现层),C是控制层。框架就是M层啦,他把一套不涉及任何业务相关的东西都写好了包装起来,你去用就可以了,C的控制层,他是没法写的,因为不同的系统有不同的业务逻辑,框架不可能帮你把业务逻辑也写进去啦。
就好比你盖房子的架子,他只能做到一个架子,不是因为他不能完全弄好,而是因为他没法去加,他也不知道你到底是需要什么颜色的瓦片,但是相比来看,框架把很多复杂的东西都弄好了,你只要在上面添加你独有的东西就可以了。
综上所述,框架可以理解为一个毛坯房,有了这个毛坯房你可以将他装修成自己想要的样子,而不需要再一砖一瓦的去盖房子(省略了你盖房子主体架构这些步骤)。
2.框架的作用是什么?
框架可以帮助省略掉一些基本的相同底层代码的反复书写,只需调用框架的方法就可以实现你想要的功能。
3.为什么要学习框架?
学习框架的目的就是提高项目的编写效率,使你可以有更多的时间去编写属于自己独特的东西,而不需要将大量的时间花费在底层代码的书写上。
源码获取
至此,我们的JavaWeb的学习(下)
就讲解完成了,源码素材可以通过关注我的微信公众号 我爱学习呀嘻嘻
,回复关键字JavaWeb源码素材
进行获取哦。
JavaWeb的学习(上):JavaWeb应用概述、Servlet容器和Servlet、HTTP协议、JSP、MVC设计模式、会话与状态管理
JavaWeb的学习(下)相关推荐
- JavaWeb笔记-备份下
JavaWeb笔记-备份下 html 简介: 超文本标记语言 Hyper Text Markup Language 网页语言 超文本:超出文本的范畴,使用html可以轻松实现 标记:html所有操作都 ...
- [硬核]卷起来!两万六千字总结的JavaWeb核心技术学习笔记
文章目录 前言 http协议笔记 JavaWEB笔记_1 JavaWEB笔记_2(JSP) JavaWEB笔记_3(web项目) Servlet Tomcat笔记 总结 前言 大家好,我是ChinaM ...
- android service 学习(下)
android service 学习(下) 通常每个应用程序都在它自己的进程内运行,但有时需要在进程间传递对象,你可以通过应用程序UI的方式写个运行在一个不同的进程中的service.在android ...
- 【深度学习下一大突破】吴恩达对话 Hinton、Bengio、Goodfellow(视频)
[深度学习下一大突破]吴恩达对话 Hinton.Bengio.Goodfellow(视频) [日期:2017-08-11] 来源:新智元 作者: [字体:大 中 小] [新智元导读]吴恩达深度 ...
- SpringBoot的全局异常处理的优雅吃法!要进来学习下吗
SpringBoot的全局异常处理的优雅吃法!要进来学习下吗 SpringBoot全局异常准备 开发准备 环境要求 JDK :1.8 SpringBoot :1.5.17.RELEASE 首先还是Ma ...
- 只会使用 WaitGroup?你应该学习下 ErrGroup!
有句话叫"看不起.看不清.追不上".近几年,关于 Go 与 Java 还有 C 的对比和讨论愈演愈烈,但不可否认的是,在十年多的时间里,Go 语言发展势头强劲,凭借其简洁.高效的特 ...
- python 网页版笔记_系统学习下python网络爬虫 笔记一
系统学习下python网络爬虫的知识 1.爬虫的定义 Web Spider,把互联网定义为一个蜘蛛网,网络蜘蛛通过网页的链接地址来寻找网页. 具体过程:从网站的某一个网页(通常是首页)开始,读取网页的 ...
- 学会了PowerBI简单的托托拽拽,是时候学习下DAX了
学会了PowerBI简单的托托拽拽,是时候学习下DAX了 不学好DAX,PowerBI对你来说就是个娱乐工具. 对于学习PowerBI来说,看起来一切都很简单,但是不会DAX的话你永远不能说自己已经会 ...
- Java的学习(下)
JAVA的学习(下) 2019版尚硅谷Java入门视频教程,哔哩哔哩链接:https://www.bilibili.com/video/BV1Kb411W75N?p=5 十一.Java集合 11-1 ...
最新文章
- H5拍照、预览、压缩、上传采坑记录
- HDU 5298 Solid Geometry Homework 暴力
- 购买Entrust SSL 数字证书?你怎么看?
- python 爬取直播弹幕视频_python爬取斗鱼B总直播弹幕
- datatable如何生成级联数据_通过源码分析Mybatis是如何返回数据库生成的自增主键值?...
- ucos 消息队列代码详解_用python实现 多进程队的列数据处理详解,零基础记得都收藏哦
- xfce4终端的字体颜色修改
- win10电脑黑屏只有鼠标箭头_电脑黑屏后屏幕只有鼠标怎么办呢?
- c++ 圆上任意点坐标计算_线性代数总结 第三章 向量代数与几何计算(空间平面和直线)...
- 大众宣布成立欧洲公司 负责旗下电动汽车电池业务
- Android 创建自己的Camera App
- php 自动选择时间的代码,JavaScript_extjs 时间范围选择自动判断的实现代码,extjs中 有时需要选择一个日期 - phpStudy...
- CMMI5 2.0版本是什么 做什么
- 便捷开票二维码应用简介
- 优化vue项目打包的chunk.js 和 chunk-vonder.js
- 【科普】中医药治疗重症肌无力的独特优势
- 网页游戏运营模式研究
- WFP之关联上下文数据以及注意事项
- 如何运营高效的社群?
- 实现用户在网页中给我的QQ邮箱发邮件