系统架构分类
- C/ S - B/ S
- C/ S:Client/ Server
优点:速度快,大部分数据已集成到客户端软件中,只需要从服务器上传送少量数据即可。
速度很快,用户体验好。
大部分的数据集成到了客户端,相对安全。
C/ S的客户端界面可以非常炫
缺点:升级需要每个客户端都升级,升级麻烦
需要安装特定的客户端软件,才能访问服务器
- B/ S:Browser/ Server
优点:不需要安装特定的客户端软件,只要有浏览器就行,客户在这一方面体验不错,
升级只需升级服务器端,方便。
缺点:所有数据全部集成在服务器端,一旦发生不可抗力,数据丢失,相对来说不安全
速度慢,用户体验差
娱乐系统适合使用C/ S架构,企业内部的系统适合使用B/ S架构。
Tomcat
Tomcat配置:
配置bin目录和CATALINA_HOME变量,目的是在命令窗口直接执行服务器命令
配置bin目录,路径是到bin路径下
配置CATALINA_HOME:路径是到根路径下
Tomcat服务器目录结构:
1. bin:
bin目录用来存放tomcat的命令,主要有两大类
一类是以. sh结尾的( linux命令) , 另一类是以. bat结尾的(windows命令)。
- startup 用来启动tomcat
- shutdown 用来关闭tomcat
2. conf:
conf目录主要是用来存放tomcat的一些配置文件。
- server. xml可以设置端口号、设置域名或IP、默认加载的项目、请求编码
- web. xml可以设置tomcat支持的文件类型
- context. xml可以用来配置数据源之类的
- tomcat- users. xml用来配置管理tomcat的用户与权限
- 在Catalina目录下可以设置默认加载的项目
3. lib:
lib目录主要用来存放tomcat运行需要加载的jar包。
4. logs:
logs目录用来存放tomcat在运行过程中产生的日志文件,非常重要的是在控制台输出的日志。
(清空不会对tomcat运行带来影响)
在windows环境中,控制台的输出日志在catalina. xxxx- xx- xx. log文件中
在linux环境中,控制台的输出日志在catalina. out文件中
5. temp:
temp目录用户存放tomcat在运行过程中产生的临时文件。(清空不会对tomcat运行带来影响)
6. webapps:
webapps目录用来存放应用程序,当tomcat启动时会去加载webapps目录下的应用程序。
可以以文件夹、war包、jar包的形式发布应用。
当然,也可以把应用程序放置在磁盘的任意位置,在配置文件中映射好就行。
7. work:
work目录用来存放tomcat在运行时的编译后文件,例如JSP编译后的文件。
清空work目录,然后重启tomcat,可以达到清除缓存的作用。
第一个WebApp
在html中的超链接,完整的可以写成:< a href= "http://localhost:8080/app01/login.html" > Login< / a>
为了代码的更加通用,可以直接从部署的项目名开始写,前面的IP地址和端口号可以省略,但要注意省略之后是以“/ ”开头
Servlet
Serv表示服务器端,let表示小程序
就是sum公司制定的Web服务器和Web服务器端的java小程序之间的接口,其中有五个方法需要重写:
void destroy ( ) ;
ServletConfig getServletConfig ( ) ;
String getServletInfo ( ) ;
void init ( ServletConfig config) ;
void service ( ServletRequest request, ServletResponse response) ;
第一个带有Servlet的WebApp
WebAp的目录结构:
最重要的:WEB-INFO文件夹、以及html文件夹、css文件夹、js文件夹等文件夹
WEB-INF文件夹里面有:
classes文件夹--->存放字节码文件
lib文件夹------->存放程序运行所需要的库(如数据库驱动);
web.xml--------->配置文件,写的是请求路径与绑定的从servlet文件(Java文件)
Tomcat服务器的lib和webapp的lib目录:
Tomcat服务器目录的lib是Tomcat的classpath,是全局的
每一个webapp也有一个lib,相当于是项目自己的classpath,是局部的
web.xml文件编写:
<?xml version="1.0" encoding="UTF-8"?>
< web-app 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-app_4_0.xsd"
version = " 4.0" >
< servlet>
< servlet-name> ThisIsHelloServlet</ servlet-name>
< servlet-class> cn.qkmango.HelloServlet</ servlet-class>
</ servlet>
< servlet-mapping>
< servlet-name> ThisIsHelloServlet</ servlet-name>
< url-pattern> /hello/servlet/test</ url-pattern>
< url-pattern> /hello/servlet</ url-pattern>
</ servlet-mapping>
</ web-app>
web.xml文件主要配置请求路径和Servlet类名之间的绑定关系
web.xml文件在Tomcat服务器启动阶段被解析
web.xml文件解析失败,会导致webapp启动失败
web.xml文件中的标签不能随意编写
web.xml文件中的标签也是sun公司指定的Servlet规范
一个webapp只有一个web.xml
将响应结果输出到浏览器中
将内容输出到浏览器的三个步骤:
1. 解决中文乱码问题, 设置内容类型和字符集
因为writer是从servletResponse获取的,所以在获取之前进行设置
servletResponse. setContentType ( "text/html;charset=UTF-8" ) ;
2. 获取流对象,直接指向浏览器客户端
PrintWriter writer = servletResponse. getWriter ( ) ;
3. 将内容输出到浏览器
writer. print ( ) ;
import javax. servlet. *;
import java. io. IOException;
import java. io. PrintWriter;
public class WelcomeServlet implements Servlet {
@Override
public void init ( ServletConfig servletConfig) throws ServletException { }
@Override
public ServletConfig getServletConfig ( ) {
return null;
}
@Override
public void service ( ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
servletResponse. setContentType ( "text/html;charset=UTF-8" ) ;
PrintWriter writer = servletResponse. getWriter ( ) ;
writer. print ( "<html>" +
"<head><title>welcome欢迎</title></head>" +
"<body><h1>welcome Page欢迎页面</h1></body>" +
"</html>" ) ;
}
@Override
public String getServletInfo ( ) {
return null;
}
@Override
public void destroy ( ) { }
}
编写JDBC连接到数据库
注意把jar包导入到对应的位置,最好是能够检查一下,如果使用了数据库连接池,那么同时也要导相应的jar包,还有数据库的驱动jar包。
Eclipse中项目默认是在: F: \JAVA\EclipseWorkSpace\. metadata\. plugins\org. eclipse. wst. server. core\tmp0\wtpwebapps中但是可以更改默认配置。
Servlet生命周期
生命周期?
一个程序从创立到销毁经历的所有过程
Servlet对象的生命周期是谁来管理的?
Servlet对象的生命周期,包括Servlet对象方法的调用,javaweb程序员是无权干涉的。
Servlet对象从最初创建到方法的调用及对象的销毁,整个过程都是web容器( Web Container) 来管理的。
默认情况下,Servlet对象在web服务器启动阶段不会被实例化。若希望在web服务器启动阶段实例化Servlet对象:
需要在配置文件servlet中加上‘< load- on- startup> 自然数< load- on- startup> ’,自然数越小,优先级越高)
描述Servlet对象生命周期* * * * *
1 、用户在地址栏输入URL:http: / / localhost: 8080 / adhhqk/ uqidqk
2 、web容器截取请求路径:/ adhhqk/ uqidqk
3 、web容器在上下文中找请求路径/ adhhqk/ uqidqk对应的Servlet对象
4 、若没有找到对应的Servlet对象
4.1 、通过web. xml文件中相关的配置信息,得到请求路径/ uqidqk对应的Servlet完整类名
4.2 、通过反射机制,调用Servlet类的无参数构造方法完成Servlet对象的实例化
4.3 、web容器调用Servlet对象的init方法完成初始化操作
4.4 、web容器调用Servlet对象的service方法提供服务
5 、若找到对应的Servlet对象
5.1 、web容器直接调用Servlet对象的service方法提供服务
6 、web容器关闭的时候/ webapp重新部署的时候/ 该Servlet对象长时间没有用户再次访问的时候,web容器会将该Servlet对象销毁,在销毁该对象之前,web容器会调用Servlet对象的destroy方法,完成销毁之前的准备。
总结:
Servlet类的构造方法只执行一次
Servlet对象的init方法只执行一次
Servlet对象的service方法,只要有用户请求一次,则执行一次
Servlet对象的destroy方法只执行一次
注意:
init方法执行的时候,Servlet对象已经创建好了。
destroy方法执行的时候,Servlet对象还没有被销毁,处于即将销毁。
Servlet对象是单例,但是不符合单例模式,只能称为伪单例。真单例的构造方法是私有化的。
Tomcat服务器是支持多线程的,所以Servlet对象在单实例多线程的环境下运行的。那么Servlet对象中若有实例变量,并且实例变量涉及到修改操作,那么这个Servlet对象一定会存在线程安全问题,不建议在Servlet对象中使用实例变量,尽量使用局部变量。
Servlet对象实例化之后存储到哪里了?
大多数的Web容器都是将该Servlet对象以及对应的url- pattern存储Map集合中了,在web容器中有这样一个Map集合
Map< String, Servlet>
key value
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
/ login LoginServlet对象的引用
/ delete DeleteServlet对象的引用
/ insert InsertServlet对象的引用
服务器启动阶段解析的web. xml文件,做了什么?
在web容器中有这样一个集合:Map< String, String>
key value
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
/ login login对应的全类名
/ delete delete对应的全类名
/ insert insert对应的全类名
实际上,服务器启动时就会解析web. xml文件,并且将解析的数据存放在Map集合中,当在浏览器中输入请求的路径时,web容器在容器里去找请求路径对应的Servlet对象,如果没有找到,* * 实际上不是去web. xml文件中找此路径对应的完整类名,而是去此Map集合中查找
Servlet接口中的方法写什么代码?何时使用?
1. 无参构造方法【以后就不需要考虑构造方法了,尽量别动构造方法】
2. init ( ) :
无参构造方法和`init ( ) `,两个方法执行时间几乎是相同的,都只执行一次
若系统要求对象在创建时刻执行一段特殊的程序,这段程序尽量写到init ( ) 方法中
为什么不建议将代码写到构造法中呢?
存在风险!当程序员编写构造方法的时候,可能会导致无参构造方法不存在
Servlet中的`init ( ) `方法是SUN公司为程序员专门提供的一个初始化时刻,若希望初始化时刻执行一段程序,这个程序可以编写在`inti ( ) `方法中,将来会被自动调用
3. service ( )
这个方法是必然重写的,因为这个方法需要完成业务逻辑的处理,请求的处理,以及完成响应
4. destroy ( )
这个方法是为程序员提供的一个特殊时刻,这个特殊时刻被成为对象销毁时刻;若希望在销毁时刻执行一段特殊代码,需要将这段代码写到`destroy ( ) `方法中,会被自动调用
ServletConfig接口
1. 【作为了解】Apache Tomcat服务器实现了Servlet规范,Tomcat服务器写了一个ServletConfig接口的实现类,实现类的完整类名是`org. apache. catalina. core. StandardWrapperFacade`
2. Javaweb程序员在编程的时候,一直是面向ServletConfig接口去完成调用的,不需要关心具体的实现类,只需要学习ServletConfig接口有哪些可以使用的方法。
- webapp放到Tomcat服务器中,ServletConfig的实现类是:`org. apache. catalina. core. StandardWrapperFacade`
- webapp放到JBOSS服务器中,ServletConfig的实现类可能是另外一个类名了
3. 怎么理解Tomcat服务器?
Tomcat服务器是一个实现了Servlet规范和JSP规范的容器
ServletConfig到底是什么?
ServletConfig是一个Servlet对象的配置信息对象,ServletConfig对象中封装了一个Servlet对象的配置信息
Servlet对象的配置信息在web. xml文件中
一个Servlet对象对应一个ServletConfig对象对象,100 个Servlet对象对应100 个ServletConfig对象
如何在`service ( ) `方法中使用`init ( ) `方法中的`servletConfig`参数对象
在`init ( ) `方法中完成:局部变量servletConfig赋值给实例变量servletConfig: this . config = config;
在`getServletConfig ( ) `,提供公开的get方法,目的是供子类使用,只需要修改return 返回值即可: return config;
ServletConfig接口中的方法
String `getInitParameter ( String name) `
通过name,获取初始化参数name对应的value
Enumeration `getInitParameterNames ( ) `
获取初始化参数的name集合。遍历用hasmoreElements ( ) ;
String `getServletName ( ) `
获取servletName,`< servlet- name> servletName< / servlet- name> `
ServletContext `getServletContext ( ) `
获取ServletContext【Servlet上下文】对象
`< init- param> `标签,初始化参数
`< init- param> `标签是初始化参数,定义在`< servlet> `标签中
`< init- param> `标签内还有`< param- name> `表示key,`< param- value> `表示value
`< init- param> `定义的参数属于某一个 Servlet
String value = servletConfig. getInitParameter ( name) 获取的就是`< init- param> `中的参数
这些信息封装在ServletConfig对象中
ServletContext接口
1. `javax. servlet. ServletContext`接口,Servlet规范
2. Tomcat服务器对ServletContext接口的实现类完整类名是:`org. apache. catalina. core. ApplicationContextFacade`
javaweb程序员只需要面向ServletContext接口调用方法即可,不需要关心Tomcat具体的实现
ServletContext到底是什么?什么时候被创建?什么时候被销毁?创建几个?
- ServletContext被译为:Servlet上下文
- 一个webapp只有一个web. xml文件,web. xml文件服务器启动阶段被解析
- 一个webapp只有一个ServletContext对象,ServletContext对象在服务器启动阶段被实例化
- ServletContext在服务器关闭的时候被销毁
- ServletContext对应的是web. xml文件,是web. xml文件的代表
- ServletContext是所有Servlet对象四周环境的代表,被所有Servlet共享
- 所有用户若想共享同一个数据,可以将数据放到ServletContext对象中(写到web. xml文件中,或后期通过方法添加)
- 一般放到ServletContext对象中的数据不建议涉及到修改操作的,以为ServletContext是多线程共享的一个对象,修改的时候会存在线程安全问题
ServletContext接口中有哪些常用方法
- void `setAttribute ( String name, Object object) `
向ServletContext中添加数据
- Object `getAttribute ( String name) `
从ServletContext中获取数据
- void `removeAttribute ( String name) `
从ServletContext中移除数据
- String `getInitParameter ( String name) `
从ServletContext中获取name所对应的value初始化参数( \< context- param> 标签中)
- Enumeration `getInitParameterNames ( ) `
从ServletContext中获取name所对应的value初始化参数( \< context- param> 标签中) , 遍历用hasmoreElements ( )
- String `getRealPath ( String path) `
获取文件绝对路径
ServletContext范围可以完成跨用户传递数据
`< context- param> `上下文参数,定义的参数属于全局,所有Servlet共享
`< param- name> `表示参数的name(key)`< / param- name> `
`< param- value> `name所对应的value`< / param- value> `
`< context- param> `
- 这些参数信息封装在ServletContext对象中
ServletContext application = config. getServletContext ( ) ;
application. getRealPath ( "/资源路径" ) ;
Servlet、ServletConfig、ServletContext之间的关系
- 一个Servlet对应一个ServletConfig对象
- 所有的Servlet共享一个ServletContext对象
欢迎页面
欢迎页面是怎么设置的?
假设在webapp/html目录下创建welcome.html,想让welcome.html作为整个webapp的欢迎页面,应该在web.xml文件中添加如下标签
欢迎页面可以设置多个,越靠上越优先,当前面的欢迎页面找不到时才使用后面的欢迎页面
< welcome-file-list>
< welcome-file> html/welcome.html</ welcome-file>
< welcome-file> welcome2.html</ welcome-file>
</ welcome-file-list>
欢迎页面可以是任何一种web资源
欢迎页面不仅可以是html文件,也可以时任何一种web资源,如Servlet
欢迎页面有全局配置和局部配置
全局配置:`CATALINA_HOME/conf/web.xml`
局部配置:`CATALINA_HOME/webapps/webapp/WEB-INF/web.xml`
若有局部配置,优先使用局部配置(就近原则)
若在web目录中有index.html、index.htm、index.jsp文件,这些都是默认的欢迎页面,都在全局配置中已经配置过了,即全局配置中,默认以这些文件为欢迎页面
常见错误代码
-404 Not Found 资源未找到,一般是路径写错。
-500 Server Inner Error 服务器内部错误,一般都是服务器Java程序出现异常
404和500是HTTP协议状态码,是W3C制定的,正常响应的HTTP协议状态码是200
可以在web.xml中添加错误页面,出现错误跳转到指定页面。
< error-page>
< error-code> 404</ error-code>
< location> /errorPage/404.html</ location>
</ error-page>
GenericServlet适配器
缺省适配器
目前我们所有的Servlet类直接实现了javax. servlet. Servlet接口,但是这个接口中有很多方法但是可能方法不需要。导致直接实现Servlet接口的代码丑陋,所以有必要在中间添加一个适配器,以后所有的Servlet类不再直接实现Servlet接口,而而是去继承适配器
适配器可以让代码优雅之外,我们还可以在适配器中提供大量的方法,子类继承之后,可以在子类中直接使用,方便编程
自定义GenericServlet类(适配器):
问题:为了让适配器类中`init ( ServletConfig) `中的代码生效,而被final 修饰限制不被重写,那么怎么在初始化时刻执行一段代码呢?
解决:`init ( ) `方法为`init ( ServletConfig) `同名的重载方法,原本的`init ( ServletConfig) `方法为了使其中的代码不被覆盖重写而失效,所以添加了`final `修饰,但是使得`init ( ServletConfig) `无法重写而过于局限,所以我们扩展一个同名的`init ( ) `方法供程序员重写,`init ( ) `会被`init ( ServletConfig) `调用,这样我们只需要重写`init ( ) `即可,若在Servlet初始化时刻需要执行一段特殊的代码,建议重写此无参数的`init ( ) `方法
SUN提供的GenericServlet类(适配器):
SUN公司已经为我们准备了官方的GenericServlet类-- > `javax. servlet. GenericServlet`
HTTP协议
什么是HTTP协议?
- 超文本传输协议
- 浏览器和服务器之间的一种通讯协议
- 该协议时W3C负责制定的,其本质上就是数据传送格式。浏览器和服务器都必须按照这种格式接收与发送数据
1.0 和1.1 版本区别
1.0 在应对有图片的资源的时候需要跑两趟,而1.1 只需要一趟
状态码:
1 xx:请求已到达服务器,但未完成,需要再次请求
2 xx:请求已到达服务器,并且已完成
3 xx:服务器内部资源重定向
4 xx:资源找不到
5 xx:服务器内部异常,代码异常
手动设置状态码:
只显示状态码:response. setStatus ( xxxx) ;
设置状态码的同时加上提示语句:response. sendError ( xxx, "提示" ) ;
HTTP协议包括几部分?
请求协议:
- 请求行:请求方式 URI 协议版本号 `POST / webapp10/ login HTTP/ 1.1 `
- 请求报头
- 空白行
- 请求体
响应协议:
- 状态行:协议版本号 状态码 描述信息
- 响应报头
- 空白行
- 响应体
空白行是专门用来分隔消息报头和请求体的
响应协议中的状态码:404 - 资源未找到 500 - 服务器内部错误 200 - 响应成功,正常结束
响应报头常见使用:
使用Location进行跳转,需要先设置服务器状态码为302
response. setStatus ( 302 ) ; -- - > response. setHeader ( "Location" , "跳转网址" ) ;
使用refresh进行延时跳转
response. setHeader ( "Refresh" , "时间;跳转网址" ) ;
使用Content- Type显示服务器图片( 注意图片放在src下)
response. setHeader ( "Content-Type" , "jpg/image/..." ) ;
Web中读取文件使用类加载器:this . getClass ( ) . getClassLoader ( ) . getResourceAsStream ( "文件" ) ;
web中输出流使用:ServletOutputStream out = response. getOutputStream ( ) ;
开始边读边写
使用Content- Disposition下载内容
response. setHeader ( "Content-Disposition" , "attachment;filename=文件名" ) ; 然后流操作
注意:
ServletOutputStream out = response. getOutputStream ( ) ; 字节流
PrintWriter out = response. getWriter ( ) ; 字符流
注意:这两个流不能同时使用。
get请求和post请求:
什么情况下浏览器发送的请求是GET请求,什么情况下浏览器发送的请求是POST请求?
只有当使用表单form,并且method属性设置为"post" ,才是POST请求方式,其余剩下的所有请求都是GET请求
GET请求和POST请求有什么区别?
GET请求在请求行上提交数据,格式`uri? name= value& name= value`,这种提交方式最终提交的数据会显示在浏览器地址栏上
POST请求在请求体中提交数据,相对安全,提交格式`name= value& name= value`,这种提交方式最终不会显示在浏览器地址栏上
GET请求在请求行上提交数据,所以GET请求提交的数据长度有限制
POST请求在请求体中提交数据,所以POST请求提交的数据没有长度限制【POST可以提价大数据】
GET请求只能提交字符串数据,POST请求可以提交任何类型的数据,包括视频. . . ,所以文件上传必须使用POST请求
GET请求最终的结果,会被浏览器缓存收纳,而POST不会被缓存收纳
GET请求和POST请求应该如何选择?
- 有敏感数据 POST
- 传送的数据不是普通字符串 POST
- 传送的数据非常多 POST
- 这个请求是为了修改服务器端资源 POST
- GET请求多数情况下是从服务器中读取资源,这个读取的资源在短时间内不会发送变化,所以GET请求最终的结果会被浏览器缓存起来
- POST请求是为了修改服务器端的资源,而每一次修改结果都是不同的,最终结果没有必要被浏览器缓存
浏览器将资源缓存后,缓存的资源是和某个特定的路径绑定在一起的,只要浏览器再发送这个相同的请求路径,这个时候浏览器就会去缓存中获取资源,不再访问服务器,以这种方式降低服务器的压力,提高用户体验。
但是有的时候我们并不希望走缓存,希望每一次重新访问服务器,可以在请求路径后面添加时间戳,例如:`http: / / ip: port/ oa/ system/ logout? timetamp= 1234564635423 ` 怎么获取毫秒值:new Date ( ) . getTime ( ) ;
HttpServlet
SUN公司为我们提供了一个类来解决判断前后端请求方式是否一致的类:
`javax. servlet. http. HttpServlet`
我们写的XxxServlet继承HttpServlet后,后端需要的是什么请求,那么我们就重写对应的`doPost ( ) `/ `doGet ( ) `方法
`doPost ( ) `/ `doGet ( ) `方法内就是我们的业务代码,`doXXX ( ) `可以看作`main ( ) `方法
代码不在`service ( ) `内编写了,不需要重写`service ( ) `方法
HttpServlet中重载的两个`service ( ) `方法并不需要也没有理由去重写这两个方法
当浏览器发送的请求方式和后台处理方式不同时,会出现一个错误,代号:405
自定义的HttpServlet ( 帮助理解原理)
public class HttpServlet extends GenericServlet {
@Override
public void service ( ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request = ( HttpServletRequest) req;
HttpServletResponse response = ( HttpServletResponse) res;
service ( request, response) ;
}
public void service ( HttpServletRequest request, HttpServletResponse response) throws IOException {
String method = request. getMethod ( ) ;
if ( "POST" . equals ( method) ) {
doPost ( request, response) ;
} else if ( "GET" . equals ( method) ) {
doGet ( request, response) ;
}
}
public void doPost ( HttpServletRequest request, HttpServletResponse response)
throws IOException {
response. setContentType ( "text/html;charset=UTF-8" ) ;
response. getWriter ( ) . print ( "应当发送GET请求" ) ;
throw new RuntimeException ( "应当发送GET请求" ) ;
}
public void doGet ( HttpServletRequest request, HttpServletResponse response)
throws IOException {
response. setContentType ( "text/html;charset=UTF-8" ) ;
response. getWriter ( ) . print ( "应当发送POST请求" ) ;
throw new RuntimeException ( "应当发送POST请求" ) ;
}
}
此时编写了一个方法继承了自定义的HttpServlet
- 假设前端发送的是POST请求
`service ( ServletRequest, ServletResponse) ` 将两个参数强转为带有Http的接口,之后执行
`service ( HttpServletRequest, HttpServletResponse) `获取请求方式POST并通过判断执行重写的doPost ( ) 方法
`doPost ( HttpServletRequest, HttpServletResponse) ` 执行业务代码
- 假设前端发送的是GET请求
`service ( ServletRequest, ServletResponse) ` 将两个参数强转为带有Http的接口,之后执行
`service ( HttpServletRequest, HttpServletResponse) `获取请求方式GET并通过判断执行未被重写的doGet ( ) 方法
`doGet ( ) ` 报错,将错误信息输出到控制台和前端页面
模版方法设计模式(templateMethod)
模版方法,定义核心算法骨架,具体的实现步骤延迟到子类中完成
public abstract class Person {
public final void templateMethod ( ) {
do1 ( ) ;
do2 ( ) ;
do3 ( ) ;
}
protected abstract void do1 ( ) ;
protected abstract void do2 ( ) ;
protected abstract void do3 ( ) ;
}
模版方法设计模式属于行为行设计模式
模版方法有一个特点:`doXXX ( ) `
模板方法设计模式的主要作用:
1. 核心算法得到保护
2. 核心算法得到复用
3. 在不改变算法的前提下,却可以重新定义算法步骤的具体实现
模板方法设计模式的经典例子:
- Servlet规范中的HttpServlet
- HttpServlet就是一个非常典型的模板方法设计模式
- HttpServlet是一个模板类
- 其中的service ( HttpServletRequest, HttpServletResponse) 方法是典型的模板方法,该方法中定义了核心算法骨架,doGet ( ) 、doPost ( ) . . . . . . 具体的实现细节延迟到子类中完成
MVC架构
生活中的三层架构:(服务员,厨师,采购)
优点:各司其职,互不干扰,工作效率高,任意环节出现问题有相应的责任人,与他人无关。
缺点:员工越多,成本越高。
软件中的三层架构:(表示层,业务逻辑层,数据访问层)
表示层:与用户交流的页面,相当于服务员
业务逻辑层:实现逻辑控制,相当于厨师
数据访问层:与数据库交互,相当于采购
优点:
1 )结构清晰,降低耦合
2 )可维护性高,可扩展性高
3 )有利于团队开发
4 )适应需求变化
缺点:
1 )代码量增加
2 )降低系统性能
M:model V:view C:controller
MVC与三层架构的关系
表示层:view,controller
业务逻辑层:controller
数据访问层:model
使用MCV搭建项目目录
表示层:HTML或者JSP放到WebContent中,com. ujiuye. servlet
业务逻辑层:com. ujiuye. servlet,com. ujiuye. service
数据访问层:com. ujiuye. dao
实体类:com. ujiuye. entity
工具类:com. ujiuye. util
测试类:com. ujiuye. test
HttpServletRequest接口
1. HttpServletRequest是一个接口,Servlet规范中重要的接口之一
2. 继承关系:public interface HttpServletRequest extends ServletRequest
3. HttpServletRequest接口的实现类时Web容器负责的,Tomcat服务器有自己的实现。所以程序员还是只需要面向HttpServletRequest接口调用方法即可,不需要关心具体的实现类
4. HttpServletRequest这个对象中封装了哪些信息?
封装了HTTP请求协议的全部内容:
- 请求方式
- URI
- 协议版本号
- 表单提交的数据
. . . . . .
5. HttpServletRequest一般对象的名字叫做:request;
HttpServletRequest对象代表一次请求,一次请求执行一次service ( ) 方法,对应一个request对象,100 个请求对应100 个request对象,所以request对象的生命周期是短暂的;
什么是一次请求?到目前为止,我们可以这样理解一次请求:在网页上点击超链接,到最终网页停下来,这就是一次完整的请求;(后面学习重定向,浏览器会自动跳转到其他地址,会重新发送新的请求,这句话就不正确了)
6. 获取用户信息,表单提交的这些数据被自动封装在request对象中了
表单数据是这样的格式提交的,POST请求,在请求体中提交,数据格式:
username= admin& password= 123 & sex= boy& interest= sport& interest= music& grade= gz& introduce= student
表单提交的数据会自动封装到request对象中,request对象中有一个Map集合,存储这些数据:
Map< String, String[ ] >
key value(value是一维数组)
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
username { "admin" }
password { "123" }
sex { "boy" }
interest { "sport" , "music" }
grade { "gz" }
introduce { "IAmAStudent" }
HttpServletRequest中常用的方法:
String getParameter ( String name) 获取key对应的一维数组的首元素
Map getParameterMap ( ) 获取request对象中的Map集合
Enumeration getParameterNames ( ) 获取所有的Map集合中所有的key
String[ ] getParameterValues ( String name) 返回String数组,数组包含key对应的多个value值
String getContextPath ( ) 获取上下文路径(web项目根路径)
String getMethod ( ) 获取浏览器请求方式
String getRequestURI ( ) 获取请求的URI
StringBuffer getRequestURL ( ) 获取请求的URL
String getServletPath ( ) 获取请求的ServletPath,即servlet对应的请求路径
String getRemoteAddr ( ) 获取客户端IP地址
Object getAttribute ( String name) 从此次请求对应的request对象范围中获取数据
void setAttribute ( String name, Object o) 从此次请求对应的request对象范围中存储数据
void removeAttribute ( String name) 从此次请求对应的request对象范围中删除数据
RequestDispatcher getRequestDispatcher ( String path) 获取请求转发器
请求转发:
1. 获取请求转发器对象、2. 调用请求转发器的`forward ( ) `方法即可完成转发
RequestDispatcher requestDispatcher = request. getRequestDispatcher ( "/b" ) ;
requestDispatcher. forward ( request, response) ;
void setCharacterEncoding ( String env) 覆盖此请求正文中使用的字符编码的名称
HttpSession getSession ( ) 返回与此请求关联的当前会话,或者如果该请求没有会话,则创建一个。
Cookie[ ] getCookies ( ) 返回一个数组,其中包含Cookie 客户端与此请求一起发送的所有对象。
关于范围对象的选择:
ServletContext 应用范围极大,可以跨用户传递数据,整个webapp只有一个ServletContext对象
ServletRequest请求范围小,只能在同一个请求中传递数据【跨Servlet传递数据,需要使用请求转发技术】
优先选择使用ServletRequest传递数据
文件上传:就是复制一份源文件到指定的位置去:
步骤:
1 、表单的method属性的值必须是post,在表单上加上enctype,值为multipart/ form- data
2 、在Servlet上加上@MultipartConfig
3 、写代码:
Part part = request. getPart ( "表单file中的name" ) ;
String header = part. getHeader ( "Content-Disposition" ) ;
String fileName = header. substring ( header. indexOf ( "filename" ) + 10 , header. length ( ) - 1 )
String path = "位置" ;
File file = new File ( path) ;
if ( ! file. existe ( ) ) { file. mkdir}
part. write ( path+ "/" + UUID. randomUUID ( ) + fileName) ;
项目中出现乱码问题
数据保存过程中的乱码:
- 数据保存到数据库表中的时候,数据出现乱码
- 导致数据保存过程中的乱码包括以下两种情况:
- 前一种情况:在保存之前,数据本身就是乱码,保存到数据库表中的时候一定是乱码
- 第二种情况:保存之前,数据不是乱码,但是由于数据库本身数据库不支持简体中文,保存之后出现乱码
数据展示过程中的乱码:
最终显示到网页上的数据出现中文乱码
第一种情况:经过执行Java程序之后,Java程序负责向浏览器响应的时候,中文乱码
解决:Java程序中设置响应的内容类型,以及对应的字符字符集
response. setContentType ( "text/html;charset=UTF-8" ) ;
第二种情况:没有经过Java程序,直接访问的是html页面
解决:在html文件中使用< meta content= "text/html;charset=utf-8" >
或者< meta charset= "utf-8" >
数据传递过程中的乱码:
通用方法:
String dname = request. getParameter ( "name" ) ;
byte [ ] bytes = dname. getBytes ( "ISO-8859-1" ) ;
value = new String ( bytes, "UTF-8" ) ;
仅支持POST请求:
request. setCharacterEncoding ( "UTF-8" ) ;
仅支持GET:
修改CATALINA_HOME/ conf/ server. xml文件,
加上URLEncoding= "UTF-8" 属性,设置请求行上的编码方式,解决GET请求乱码
< Connector port= "8080"
protocol= "HTTP/1.1"
connectionTimeout= "20000"
redirectPort= "8443"
URLEncoding= "UTF-8" / >
URLencode: 是将字符通过某种字符集进行编码后,再使用百分号编码. 如字符通过UTF- 8 字符集进行编码后得到的二进制文件,然后将二进制转化为16 进制,在每一个字符前面加上% 作为分隔
UTF- 8 百分号编码
"销售部" -- -- -- > E9 94 80 E5 94 AE E9 83 A8 -- -- -- > % E9% 94 % 80 % E5% 94 % AE% E9% 83 % A8
Servlet线程安全问题
Servlet是单实例多线程环境下运行的
Servlet对象只有一个,被多个线程共享;new 出来的对象在堆空间,所有线程共享一个堆;
Servlet怎么解决线程安全问题:
1. 不使用实例变量,尽量使用局部变量
2. Servlet是单例的,所以剩下的方式只能考虑使用`synchronized `,线程同步机制
转发和重定向
转发:request. getRequestDispatcher ( "/b" ) . forward ( request, response) ;
重定向:response. sendRedirect ( request. getContextPath ( ) + "/b" ) ;
转发和重定向的区别:
- 相同点:都可以完成资源的跳转
- 不同点:
- 转发是request对象触发的,服务器内部进行转发
- 重定向是response对象触发的,要将重定向的路径相应给浏览器
- 转发是一次请求,浏览器地址栏上地址不变
- 重定向是两次请求,浏览器地址栏上的地址发生变化
- 重定向路径需要加项目名(webapp跟路径web目录)
- 转发是在本项目内部完成资源的跳转
- 重定向可以完成跨app跳转,例如可以跳转到`https: / / www. baidu. com`
什么时候采用转发,什么时候采用重定向?
大部分情况下都使用重定向
- 若想完成跨app跳转,必须采用重定向
- 重定向可以解决浏览器的刷新问题
- 若在上一个资源中向request范围中存储了数据,希望在下一个资源中从request范围中取出,必须使用转发
重定向原理是什么?
response. sendRedirect ( "/jd/login" ) ;
程序执行到以上代码,将请求路径`/ jd/ login`反馈给浏览器,
浏览器又向web服务器发送了一次全新的请求:/ jd/ login
浏览器地址栏上最终显示的地址是:/ jd/ login
重定向解决页面刷新问题
如果使用转发:
浏览器只进行一次请求,如果此时浏览器进行刷新,浏览器刷新的是最后一次请求,即提交表单的请求,
此时多次刷新浏览器,那么就会请求多次,就会执行多次Servlet,
就会多次连接数据库插入数据,导致数据重复插入
如果使用重定向:
服务器返回重定向的地址(success. html),浏览器就会请求新的地址,
一共有两次请求:提交表单的请求和重定向的请求
此时如果浏览器多次刷新,那么请求的也是重定向的success. html静态页面,
不会因为刷新而导致多次提交表单
Cookie
Cookie是什么?
- Cookie可以保存会话状态,但是这个会话状态是保留在客户端上的
- 只要Cookie清除,或者Cookie失效,这个会话状态就没有了
- Cookie是保存在浏览器客户端上的
- Cookie可以保存在浏览器的缓存中,浏览器关闭Cookie消失
- Cookie可以用保存在客户端硬盘文件中,浏览器关闭Cookie还在,除非Cookie消失
创建Cookie:
服务器创建Cookie并发送给浏览器
Cookie cookie = new Cookie ( String name, String value) ;
cookie. setMaxAge ( 60 * 60 * 60 ) ;
cookie. setPath ( "/webapp19/user" ) ;
response. addCookie ( cookie) ;
Cookie绑定路径:
在默认情况下,未设置Cookie绑定路径的Cookie,会绑定当前访问路径的"上级路径/" ,当浏览器访问这个路径,以及以这个路径作为根路径的地址时都会发送Cookie给服务器。
`cookie. setPath ( ) ; `来设置此Cookie绑定的访问路径
Cookie有效时长:
`cookie. setMaxAge ( int expiry) `
- 参数是一个整数
- 值为正数,以秒为单位指定Cookie的最长期限,Cookie存储在硬盘文件当中;
- 值为负数,则此Cookie在关闭此窗口页面后即失效;
- 如果为零,则删除此Cookie;
HttpSession
Session概述:
1. Session表示会话,不止是在javaweb中存在,只要是web开发,都会有这种机制
2. 在java中会话对应的类型是:javax. servlet. http. HttpSession 简称session/ 对话
3. Cookie可以将会话状态保存在客户端,而HttpSession可以将会话状态保存在服务器端
4. HttpSession对象是一个会话级别的对象,一次会话对应一个HttpSession对象
5. 在会话进程中,web服务器一直为当前这个用户维护着一个会话对象HttpSession
6. 在web容器中,维护了大量的HttpSession对象,换句话说,在web容器中应该有一个“Session”列表
思考:为什么当前会话中的每一次请求都可以获取到属于自己的Session会话对象?
什么是一次会话?
- 一般可以这样理解:用户打开浏览器,在浏览器上发送多次请求,直到最终浏览器关闭,表示一次完整的回话。
- 本质上理解:Session对象创建到最终超时销毁,才是真正意义的一次会话;因为即使浏览器关闭,可以通过重写URL的方式从其他电脑其他浏览器同样使用这个Session对象。
获取Session对象:
HttpSession session = request. getSession ( 无参数默认为true ) ;
注意:
request. getSession ( boolean ) 需要一个boolean 类型的参数
当参数为true ( 无参默认true ) 时,session存在则返回;如果session不存在,则创建一个新的session对象并返回
当参数为false 时,session存在则返回;如果session不存在,则返回null
Session实现原理:
1. 浏览器发送请求,服务器对应的Servlet* * 首次调用* * `request. getSession ( true ) ; `方法
1.1 服务器会创建一个Session对象,该对象代表一次会话,同时生成一个对应的Cookie对象,并且Cookie对象的name是JSESSIONID,Cookie的value是32 位长度的字符串
1.2 服务器将Cookie的value和HttpSession对象绑定到session列表中( Map集合)
1.3 服务器将Cookie发送到浏览器客户端,浏览器客户端将Cookie保存到缓存中( 只要浏览器不关闭,Cookie不会消失)
2. 浏览器再次发送请求,会自动提交缓存当中的Cookie
2.1 当服务器Servlet* * 再次调用* * `request. getSession ( ) ; `方法时获取Session对象
2.2 服务器接收到Cookie,验证Cookie的name为JSESSIONID,然后获取该Cookie的value
2.3 通过Cookie的value去session列表( Map集合) 中检索对应的HttpSession对象
Session对象在什么时候销毁?
1. web系统中引入了session超时的概念
2. 当一段时间没有用户再访问session对象,此时session对象超时,web服务器自动回收session对象
3. 设置Session对象失效时间(两次请求之间的最大时间间隔),优先级 A > B > C
A:通过Java代码实现,单位秒
HttpSession session = request. getSession ( ) ; session. setMaxInactiveInterval ( 60 * 60 ) ;
B:修改项目的web. xml文件,单位分钟
< session- config>
< session- timeout> 60 < / session- timeout>
< / session- config>
C:修改Tomcat默认配置,单位分钟,默认30 分钟,CATALINA_HOME/ conf/ web. xml
< session- config>
< session- timeout> 30 < / session- timeout>
< / session- config>
HttpSession中常用方法:
void setAttribute ( String name, Object value) 向会话范围中存储数据
Object getAttribute ( String name) 从会话范围中获取数据
void removeAttribute ( String name) 从会话范围中移除某个数据
void invalidate ( ) 销毁session对象
void setMaxInactiveInterval ( int interval) 设置session对象失效时间
ServletContext、HttpSession、HttpServletRequest对比:
1. 以上都是范围对象:
`ServletContext application` 是应用范围
`HttpSession session` 是会话范围
`HttpServletRequest request` 是请求范围
2. 三个范围的大小 application > session > request
3. application完成跨会话(用户)共享数据;
session完成跨请求共享数据,但是这些请求必须在同一个会话当中;
request完成跨Servlet共享数据,但是这些servlet必须在同一个请求当中(请求转发)
4. 使用原则:由小到大尝试,优先使用小范围
注意:
1. HttpSession对象关联的这个Cookie的name是比较特殊的,在Java中就叫做:JSESSIONID
2. 浏览器禁用Cookie会出现什么问题?怎么解决?
- 浏览器禁用Cookie,则浏览器缓存中不再保存Cookie
- 导致在同一个会话中,无法获取到对应的会话对象
- 禁用Cookie之后,每一次获取的会话对象都是新的
- 浏览器禁用Cookie之后,若还想拿到对应的Session对象,必须使用URL重写机制
怎么重写URL:
```
http: / / localhost: 8080 / webapp23/ testSession; jsessionid= 384 A8D1CE7821C76EDC445F7D029C46A
```
重写URL会给编程带来难度/ 复杂度,所以web站点是不建议禁用Cookie
使用重写URL,即使换浏览器换电脑,只要在一定时间内访问的是同一个jsessionid,就可以得到同一个Session对象
3. 浏览器关闭后,服务器端对应的session对象会被销毁吗?
- 浏览器关闭后,服务器不会销毁session对象;因为B/ S架构的系统基于HTTP协议,而HTTP协议是一种无连接/ 无状态的协议
- 什么是无连接/ 无状态?
请求的瞬间浏览器和服务器之间的通道是打开的,请求响应结束后,通道关闭;这样做的目的是降低服务器的压力
路径编写
超链接: < a href= "/项目名/资源路径" < / a>
form表单: < form action= "/项目名/资源路径" < / form> ; ;
重定向:response. sendRedirect ( "/项目名/资源路径" ) ;
转发 :request. getRequestDispatcher ( "/资源路径" ) . forward ( request, response) ;
欢迎页面 :
< welcome- file- list>
< welcome- file> index. html< / welcome- file>
< welcome- file> WelcomeServlet< / welcome- file>
< / welcome- file- list>
Servlet 路径:
< servlet>
< servlet- name> hello< / servlet- name>
< servlet- class > cn. qkmango. HelloServlet< / servlet- class >
< / servlet>
< servlet- mapping>
< servlet- name> hello< / servlet- name>
< url- pattern> / 资源路径< / url- pattern>
< / servlet- mapping>
Cookie 设置path:cookie. setPath ( "/项目名/资源路径" ) ;
ServletContext:
this . getServletConfig ( ) ;
ServletConfig config = getServletConfig ( ) ;
ServletContext context = config. getServletContext ( ) ;
context. getRealPath ( "/资源路径" ) ;
url-pattern的编写方式
一个Servlet可以编写多个url-pattern
精确匹配:
<url-pattern>/system/hello</url-pattern>
<url-pattern>/user</url-pattern>
扩展匹配:
<url-pattern>/user/*</url-pattern>
后缀匹配:
<url-pattern>*.action</url-pattern>
<url-pattern>*.do</url-pattern>
全部匹配:
<url-pattern>/*</url-pattern>
Servlet3.0注解
注解:Servlet3.0和JDK1.5及以后的版本才能使用
最简单的注解
@WebServlet("/资源名")--->相当于url-pattern,"/资源名"指向了注解的这个Servlet;
多种数据的配置
@WebServlet(url-Patterns = {"资源名1","资源名2","资源名3"},loadOnStartup = 0,
initParams = {@WebParams(name = "",value = ""),@WebParams(name = "",value = "")}
....
)
注意:同一个Servlet,要么使用web.xml文件配置,要么使用注解配置,但是不能使用两种方式同时配置。
XML
一种可扩展标记语言
XML文件的格式要求
1 )第一行必须是版本申明等信息
2 )有且仅有一个根标签
3 )不区分大小写,推荐使用小写
4 )自定义的标签不能是关键字
5 )标签之间必须正确嵌套
6 )标签名开头不能是数字
7 )标签可以有属性:属性名= ”属性值”
XML的作用
1 )配置文件
2 )结构化存储数据
3 )数据交换(典型应用:AJAX)
dom4j解析XML文件
先导包
再使用SAXReader将文件读成Document:
Document document = reader. read ( "xxx.xml" ) ;
获取根标签
Element root = document. getRootElement ( ) ;
获取子标签
List< Element> list = root. elements ( ) ;
循环获取子标签,再获取内容,
获取内容用e. element ( "标签" ) . getText ( ) ;
获取标签里面的属性用e. attributeValue ( "属性名" )
XPath解析XML文件:
XPath可以用来确定XML文档中某部分位置,它基于dom4j。
使用之前先导包
还是先使用SAXReader将文件读成Document:
Document document = reader. read ( "xxx.xml" ) ;
再使用语法( 查文档)
JSP
Java Server Page:Java服务器页面,动态网页。Java可以直接写在这个页面上。
JSP文件的执行流程:
jsp文件被第一次访问的时候:jsp文件翻译成java文件,再编译成字节码文件,执行字节码文件。
通过查看编译后的字节码发现:JSP实际上就是一个Servlet
jsp文件未被修改第N次访问:直接执行字节码文件
jsp与Servlet的区别:
1、JSP主要功能是给用户看的页面,Servlet是控制器
2、JSP被Tomcat翻译成java文件时直接赋予了九大内置对象,Servlet没有
3、JSP是一个简化版的Servlet,功能有限。Servlet功能更加全面
4、JSP不算一个纯粹的Java类,Servlet是一个纯粹的Java类
JSP页面组成:
1、HTML标签及其内容
2、Java代码
第一种:脚本(脚本的内容被翻译到了_jsp方法的内部,因此脚本中不能定义java方法)
语法:<% java代码 %>
第二种:表达式(将数据输出到浏览器上)
语法:<%=要输出的数据%>
第三种:声明
语法:<%! java代码 %>
3、JSP指令
三大指令:page,include,taglib;
语法:<%@ 指令 指令内容%>
第一种:page指令(页面描述)
language:当前页面的脚本语言
contentType:页面响应体的编码格式
pageEncoding:页面的编码格式
import:导包
errorPage:错误跳转指定
eg: <%@
page language="java" contentType="text/html;charset=utf-8" pageEncoding="utf-8" errorPage="xxx.jsp"
%>
第二种:include(包含)
注意:使用include指令包含进来的JSP页面,是不会被翻译的(先把所有的合并在一起再编译)
eg:<%@ include file="xxx.jsp" %>
第三种:taglib指令(引入其他工具)
eg:<%@ taglib uri="xxx/jstl/core" prefix="c" %>
<%@ taglib uri="xxx/jstl/functions" prefix="fn" %>
4、注释:要注意的是jsp本身的注释<%--内容--%>不会被翻译到java代码中,而其他的注释会
EL表达式
Expression Language 是为了使JSP写起来更加简单
语法:${.....}
内部能进行的运算:算术、关系、逻辑、三元、空值判断${empty xxx}
JSP九大内置对象
pageContext------->页面内容对象
request----------->请求对象
session----------->会话对象
application------->服务器对象
response---------->响应对象
config------------>初始化数据对象
out--------------->输出对象
page-------------->当前页面对象,类似于Java中的this
exception--------->异常对象
Servlet中PrintWriter与JSP中out的区别:
PrintWriter,不带缓冲区,直接写到页面上
out,有缓冲区,先到缓冲区,再到页面上
JSP四大作用域
Servlet中的作用域:
request:是请求范围
session:是会话范围
ServletContext:是应用范围
JSP中的作用域:
pageContext:针对页面,在当前页面内有效。(是JSP独有的)
request:请求范围
session:会话范围
application:应用范围
如果四大作用域中存入了相同key的数据?
按照pageContext-->request-->session-->application的顺序寻找,找到了就结束
使用EL表达式,获取指定作用域的数据:
pageContext-->pageScope
request-->requestScope
session-->sessionScope
application-->applicationScope
JSP动作标签
一共13个
需要了解的:jsp:forward,include,
其他的:jsp:attribute,body,element,fallback,getProperty,output,
param,params,plugin,setProperty,useBean
jsp:forward:跳转到某个页面
<jsp:forward page="跳转页面"></jsp:forward>
jsp:include:将某个页面包含到本页面
<jsp:include page="xxx.jsp"></jsp:include>
注意:此标签在包含时,先将所有的JSP文件翻译成java文件,再组合到一起。
include指令(静态包含)与include标签(动态包含)的区别:
1、语法不一样
2、翻译方式不一样,指令只翻译一个文件,标签翻译所有文件
3、指令的效率相对较高,标签较低
4、指令不能携带数据,标签可以
JSTL标签库
Java server pages standarded tag library (jsp标准标签库)
步骤:导jar包->在jsp页面使用taglib指令来导入需要的标签库
核心:xxxx/jstl/core
引入:<%@ taglib uri="xxx/jstl/core" prefix="c" %>
使用:
创建变量:<c:set var="name" value="xxx"></c:set>
输出:<c:out value="${name}"></c:out>
移除变量:<c:remove var="name"></c:remove>
如果:<c:if test="${3>2}">输出内容</c:if>
选择:
<c:choose>
<c:when test="xxx">输出的内容</c:when><c:otherwise>
<c:when test="xxx">输出的内容</c:when><c:otherwise>
</c:otherwise>
</c:choose>
循环(注意items双引号里面不要加空格):
<c:foreach var="u" items="${list}">
账号:${u.uname},密码:${u.pad}
</c:foreach>
格式化:xxxx/jstl/fmt
函数:xxxx/jstl/functions
引入:<%@ taglib uri="xxx/jstl/functions" prefix="fn" %>
使用:
字符串长度:${fn: length(str)}
.......
Ajax
Asynohronous JavaScirpt And Xml -- -- -- 异步的JavaScript和XML
它不是一种技术,是多种技术联合实现的产物。
Ajax是浏览器客户端上的前端技术
异步和同步有什么区别?
A线程和B线程,并发执行,谁也不等谁,这就是异步
A线程和B线程,在其中一个线程执行的时候另外一个线程需要等待,这就是同步;
传统的请求和Ajax请求有什么区别?
传统的请求都是同步的,Ajax可以做到异步请求。
Ajax经典案例:Goole的auto_complete 、 Goole的map
浏览器本身是支持多线程并发的,其中ajax请求就是一个线程。一个页面上可以同时发送多个ajax请求,多个ajax对应浏览器对个线程。
Ajax实现四步:
1 、创建Ajax核心对象XMLHttpRequest
var xhr;
if ( window. XMLHttpRequest ( ) ) {
xhr = new XMLHttpRequest ( ) ;
} else {
xhr = new ActiveXObject ( "Microsoft.XMLHTTP" ) ;
}
2 、注册回调函数
xhr. onreadystatechange = function ( ) {
if ( xhr. readyState == 4 ) {
if ( xhr. status == 200 ) {
var s = xhr. responseText;
. . . . .
} else {
alert ( xhr. status)
}
}
}
3 、开启浏览器和服务器之间的通道
xhr. open ( method, url, asyn) ;
4 、发送Ajax请求
xhr. send ( ) ;
注意:如果Ajax发送请求的方式是get, 那么为了防止第n+ 1 次访问走缓存,可以使用“加时间缀”的方式避免。
var timeStamp = new Date ( ) . getTime ( ) ; 在路径后面加的时候可以使用下划线加:? _= timeStamp& . . . . .
jQuery版AJAX
jQuery封装的AJAX常用的三种方法:
一、$. ajax ( {
url: "" ,
type: "get/post" ,
data: { "key" : "value" , "key" : "value" , . . . } ,
dataType: "响应的数据类型" ,
success: function ( ) { } ,
error: function ( ) { }
} ) ;
二、$. get ( "url" , { "key" : "value" , "key" : "value" , . . . } , function ( ) {
. . . . . . .
} , dataType) ;
三、$. post ( "url" , "key" : "value" , "key" : "value" , . . . , function ( ) {
. . . . . . . . . . .
} , dataType) ;
返回数据的格式:
text, json, html, script, jsonp, xml
表单序列化:
作用:可以获取表单中用户输入的请求。
关键字:serialize
eg: var data = $( "#form" ) . serialize ( ) ;
工具类
DBUtil:
public class DBUTils {
private DBUTils ( ) { }
static ComboPooledDataSource ds = new ComboPooledDataSource ( ) ;
static QueryRunner qr = new QueryRunner ( ds) ;
public static QueryRunner getQueryRunner ( ) {
return qr;
}
}
DateUtils:
public class DateUtils {
private DateUtils ( ) { }
public static Date stringToDate ( String time) {
Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat ( "yyyy-MM-dd" ) ;
try {
date = sdf. parse ( time) ;
} catch ( ParseException e) {
e. printStackTrace ( ) ;
}
return date;
}
public static String dateToString ( Date date) {
SimpleDateFormat sdf = new SimpleDateFormat ( "yyyy-MM-dd HH:mm:ss SSS" ) ;
return sdf. format ( date) ;
}
}
PageUtil:
public class PageUtil {
private int currPage;
private int rows;
private int index;
private int countRows;
private int countPages;
private int prevPage;
private int nextPage;
public PageUtil ( String currPage, int rows, int countRows) {
this . rows = rows;
this . countRows = countRows;
currPage ( currPage) ;
index ( ) ;
countPages ( ) ;
prevPage ( ) ;
nextPage ( ) ;
}
private void currPage ( String currPage) {
if ( currPage == null || "" . equals ( currPage) ) { this . currPage = 1 ; } else { this . currPage = Integer. parseInt ( currPage) ; } }
private void index ( ) { index = ( currPage- 1 ) * rows; }
private void countPages ( ) { countPages = ( countRows+ rows- 1 ) / rows; }
private void prevPage ( ) { if ( currPage != 1 ) { prevPage = currPage- 1 ; } else { prevPage = 1 ; } }
private void nextPage ( ) { if ( currPage != countPages) { nextPage = currPage + 1 ; } else { nextPage = countPages; } }
生成所有属性的get方法,因为只需要别人调用,不需要别人设置!
}
BaseServlet
public class BaseServlet extends HttpServlet {
protected void service ( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request. setCharacterEncoding ( "utf-8" ) ;
response. setContentType ( "text/html;charset=utf-8" ) ;
String flag = request. getParameter ( "flag" ) ;
Class theClass = this . getClass ( ) ;
try {
Method md = theClass. getDeclaredMethod ( flag, HttpServletRequest. class , HttpServletResponse. class ) ;
md. setAccessible ( true ) ;
md. invoke ( this , request, response) ;
} catch ( Exception e) { e. printStackTrace ( ) ; } } }