哎呀呀,一不小心就到基础阶段的最后一部分了呢!昨天&今天学习的主要内容是ajax,listener,filter和classloader。
目录
异步AJAX
简介
AJAX即“Asynchronous Javascript And XML”(异步 Javascript 和 XML)可以使网页实现异步更新就是不重新加载整个网页的情况下,对网页的某部分进行更新(局部刷新)。传统的网页(不使用AJAX)如果需要更新内容,必须重载整个网页页面。
AJAX = 异步 Javascript 和 XML,是一种新的思想,整合之前的多种技术,用于创建快速交互式网页应用的网页开发技术。
提一下同步和异步吧:
同步现象:客户端发送请求到服务器端,当服务器返回响应之前,客户端都处于等待、卡死状态
异步现象:客户端发送请求到服务器端,无论服务器是否返回响应,客户端都可以随意做其他事情,不会被卡死
通过使用AJAX,我们可以跳过中间那段执行代码的等待时间,从而大幅度的提高工作效率。
运行原理
页面发起请求,会将请求发送给浏览器内核中的Ajax引擎,Ajax引擎会提交请求到 服务器端,在这段时间里,客户端可以任意进行任意操作,直到服务器端将数据返回 给Ajax引擎后,会触发你设置的事件,从而执行自定义的js逻辑代码完成某种页面1的功能。
具体的步骤如下:
js原生的Ajax技术(了解)
js原生的Ajax其实就是围绕浏览器内内置的Ajax引擎对象进行学习的,要使用js原生的Ajax完成异步操作,有如下几个步骤:
- 创建Ajax引擎对象
- 为Ajax引擎对象绑定监听(监听服务器已将数据响应给引擎)
- 绑定提交地址
- 发送请求
- 接受响应数据
对于GET请求 :
// 1、创建引擎对象
var xmlhttp = new XMLHttpRequest();
// 2、绑定监听事件
xmlhttp.onreadystatechange = function() {
// 5、接收响应数据
if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var res = xmlhttp.responseText;
alert(res);
}
}
// 3、绑定跳转页面地址
xmlhttp.open("GET", "${pageContext.request.contextPath}/ajax",true);
// 4、发送请求
xmlhttp.send();
注意:如果是post提交,需要在发送请求之前设置一个头:xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); 直接复制粘贴即可,似乎是格式emmm
XMLHttpRequest对象浏览器兼容:
function getXMLhttp() {
var xmlhttp = null;
// 谷歌、火狐、IE7+
if(window.XMLHttpRequest) {// 检测浏览器是否支持XMLHttpRequset
xmlhttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
// IE旧版本浏览器
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
}
Json数据格式(重要)
json是一种与语言无关的数据交换的格式,我们使用使用ajax进行前后台数据交换或进行移动端与服务端的数据交换。
Json的格式与解析
json有两种格式:
- 对象格式:{"key1":obj,"key2":obj,"key3":obj...}
- 数组/集合格式:[obj,obj,obj...]
例如:user对象用json数据格式表示
{"username":"zhangsan","age":28,"password":"123","addr":"北京"}
List<Product> 用json数据格式表示
[{"pid":"10","pname":"小米4C"},{},{}]
注意:对象格式和数组格式可以互相嵌套
注意:json的key是字符串,value是Object
json的解析:
json是js的原生内容,也就意味着js可以直接取出json对象中的数据
Json的转换插件
将java的对象或集合转成json形式字符串
json的转换插件是通过java的一些工具,直接将java对象或集合转换成json字符串。
常用的json转换工具有如下几种:
- jsonlib
- Gson:google
- fastjson:阿里巴巴(使用最便捷)
Jquery的Ajax技术(重点)
jquery是一个优秀的js框架,自然对js原生的ajax进行了封装,封装后的ajax的操作方法更简洁,功能更强大,与ajax操作相关的jquery方法有如下几种,但开发中经常使用的是前三种:
$.ajax([options])
$.get(url, [data], [fn], [type])
$.post(url, [data], [fn], [type])
load(url, [data], [callback])
$.getJSON(url, [data], [fn])
$.getScript(url, [callback])
1.$.get(url, [data], [callback], [type])
2.$.post(url, [data], [callback], [type])
其中:
url:代表请求的服务器端地址
data:代表请求服务器端的数据(可以是key=value形式也可以是json格式)
callback:表示服务器端成功响应所触发的函数(只有正常成功返回才执行)
type:表示服务器端返回的数据类型(jquery会根据指定的类型自动类型转换)
常用的返回类型:text、json、html等
3.$.ajax( { option1:value1,option2:value2... } );
常用的option有如下:
async:是否异步,默认是true代表异步
data:发送到服务器的参数,建议使用json格式
dataType:服务器端返回的数据类型,常用text和json
success:成功响应执行的函数,对应的类型是function类型
type:请求方式,POST/GET
url:请求服务器端地址
监听器Listener
什么是监听器?
监听器就是监听某个对象的的状态变化的组件
监听器的相关概念:
事件源:被监听的对象 ----- 三个域对象 request session servletContext
监听器:监听事件源对象、事件源对象的状态的变化都会触发监听器 ---- 6+2
注册监听器:将监听器与事件源进行绑定
响应行为:监听器监听到事件源的状态变化时所涉及的功能代码 ---- 程序员编写代码
监听器有哪些?
第一维度:按照被监听的对象划分:ServletRequest域、HttpSession域、ServletContext域
第二维度:监听的内容分:监听域对象的创建与销毁的和监听域对象的属性变化的
监听三大域对象的创建与销毁的监听器
1、监听ServletContext域的创建与销毁的监听器ServletContextListener
1)Servlet域的生命周期
何时创建:服务器启动创建
何时销毁:服务器关闭销毁
2)监听器的编写步骤(重点):
- 编写一个监听器类去实现监听器接口
- 覆盖监听器的方法
- 需要在web.xml中进行配置---注册
3)监听的方法:
4)配置文件(web.xml):
5)ServletContextListener监听器的主要作用
- 初始化的工作:初始化对象初始化数据 ---- 加载数据库驱动、连接池的初始化
- 加载一些初始化的配置文件 --- spring的配置文件
- 任务调度----定时器----Timer/TimerTask
public class BirthdayListener implements ServletContextListener{
@Override
public void contextInitialized(ServletContextEvent sce) {
//当web应用启动 开启任务调动---功能在用户的生日当前发送邮件
//开启一个定时器
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// 为当前的生日的用户发邮件
//1、获得今天过生日的人
//获得今天的日期
SimpleDateFormat format = new SimpleDateFormat("MM-dd");
String currentDate = format.format(new Date());
//根据当前时间从数据查询今天过生日的人
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "select * from customer where birthday like ?";
List<Customer> customerList = null;
try {
customerList = runner.query(sql, new BeanListHandler<Customer>(Customer.class) ,"%"+currentDate+"%");
} catch (SQLException e) {
e.printStackTrace();
} //08-18
//2、发邮件
if(customerList!=null&&customerList.size()>0){
for(Customer c : customerList){
String emailMsg = "亲爱的:"+c.getRealname()+",生日快乐!";
try {
MailUtils.sendMail(c.getEmail(), "生日祝福", emailMsg);
System.out.println(c.getRealname()+"邮件发送完毕");
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
}
}, new Date(), 1000*10);
//实际开发中起始时间是一个固定的时间
//实际开发中间隔时间是1天
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
1、监听Httpsession域的创建于销毁的监听器HttpSessionListener
1)HttpSession对象的生命周期
何时创建:第一次调用request.getSession时创建
何时销毁:服务器关闭销毁 session过期 手动销毁
2)HttpSessionListener的方法
3、监听ServletRequest域创建与销毁的监听器ServletRequestListener
1)ServletRequest的生命周期
创建:每一次请求都会创建request
销毁:请求结束
2)ServletRequestListener的方法
监听三大域对象的属性变化的监听器
1、域对象的通用的方法:
setAttribute(name,value)
--- 触发添加属性的监听器的方法
--- 触发修改属性的监听器的方法
getAttribute(name)
removeAttribute(name)
--- 触发删除属性的监听器的方法
2、ServletContextAttibuteListener监听器
public class MyServletContextAttributeListener implements ServletContextAttributeListener{
@Override
public void attributeAdded(ServletContextAttributeEvent scab) {
//放到域中的属性
System.out.println(scab.getName());//放到域中的name
System.out.println(scab.getValue());//放到域中的value
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scab) {
System.out.println(scab.getName());//删除的域中的name
System.out.println(scab.getValue());//删除的域中的value
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scab) {
System.out.println(scab.getName());//获得修改前的name
System.out.println(scab.getValue());//获得修改前的value
}
}
3、HttpSessionAttributeListener监听器(同上)
4、ServletRequestAriibuteListenr监听器(同上)
对象感知监听器
与session中的绑定的对象相关的监听器
1、即将要被绑定到session中的对象有几种状态
绑定状态:就一个对象被放到session域中
解绑状态:就是这个对象从session域中移除了
钝化状态:是将session内存中的对象持久化(序列化)到磁盘
活化状态:就是将磁盘上的对象再次恢复到session内存中
2、绑定与解绑的监听器HttpSessionBindingListener
public class Person implements HttpSessionBindingListener{
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
//绑定的方法
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("person被绑定了");
}
@Override
//解绑方法
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("person被解绑了");
}
}
3、钝化与活化的监听器HttpSessionActivationListener
可以通过配置文件指定对象钝化时间 --- 对象多长时间不用被钝化
在META-INF下创建一个context.xml
<Context>
<!-- maxIdleSwap:session中的对象多长时间不使用就钝化 -->
<!-- directory:钝化后的对象的文件写到磁盘的哪个目录下 配置钝化的对象文件在 work/catalina/localhost/钝化文件 -->
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="itcast205" />
</Manager>
</Context>
钝化和活化session对象到本地:
public class Customer implements HttpSessionActivationListener,Serializable{
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
//钝化
public void sessionWillPassivate(HttpSessionEvent se) {
System.out.println("customer被钝化了");
}
@Override
//活化
public void sessionDidActivate(HttpSessionEvent se) {
System.out.println("customer被活化了");
}
}
过滤器Filter
简介
filter是对客户端访问资源的过滤,符合条件放行,不符合条件不放行,并且可以对目标资源访问前后进行逻辑处理。
快速入门
步骤(给出自动登录的filter作为示例):
1.编写一个过滤器的类实现Filter接口
2.实现接口中尚未实现的方法(着重实现doFilter方法)
public class AutoLoginFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession session = req.getSession();
//获得cookie中用户名和密码 进行登录的操作
//定义cookie_username
String cookie_username = null;
//定义cookie_password
String cookie_password = null;
//获得cookie
Cookie[] cookies = req.getCookies();
if(cookies!=null){
for(Cookie cookie : cookies){
//获得名字是cookie_username和cookie_password
if("cookie_username".equals(cookie.getName())){
cookie_username = cookie.getValue();
//恢复中文用户名
cookie_username = URLDecoder.decode(cookie_username, "UTF-8");
}
if("cookie_password".equals(cookie.getName())){
cookie_password = cookie.getValue();
}
}
}
//判断username和password是否是null
if(cookie_username!=null&&cookie_password!=null){
//登录的代码
UserService service = new UserService();
User user = null;
try {
user = service.login(cookie_username,cookie_password);
} catch (SQLException e) {
e.printStackTrace();
}
//将登录的用户的user对象存到session中
session.setAttribute("user", user);
}
//放行
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
3.在web.xml中进行配置(主要是配置要对哪些资源进行过滤)
<filter>
<filter-name>AutoLoginFilter</filter-name>
<filter-class>com.ithiema.web.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
API详解
filter生命周期
Filter接口有三个方法,并且这个三个都是与Filter的生命相关的方法
init(Filterconfig):代表filter对象初始化方法 filter对象创建时执行
doFilter(ServletRequest,ServletResponse,FilterCha):代表filter执行过滤的核心方法,如果某资源在已经被配置到这个filter进行过滤的话,那么每次访问这个资源都会执行doFilter方法
destory():代表是filter销毁方法 当filter对象销毁时执行该方法
Filter对象的生命周期:
Filter何时创建:服务器启动时就创建该filter对象
Filter何时销毁:服务器关闭时filter销毁
API详解
1.init(FilterConfig)
其中参数config代表 该Filter对象的配置信息的对象,内部封装是该filter的配置信息。
2.destory()方法
filter对象销毁时执行
3.doFilter方法
doFilter(ServletRequest,ServletResponse,FilterChain)
其中的参数:
ServletRequest/ServletResponse:每次在执行doFilter方法时 web容器负责创建一个request和一个response对象作为doFilter的参数传递进来。该request个该response就是在访问目标资源的service方法时的request和response。
FilterChain:过滤器链对象,通过该对象的doFilter方法可以放行该请求
Filter的配置
具体的配置,上面已经给过了,这里进行一下各个参数的介绍:
url-pattern配置时
1.完全匹配 /sertvle1
2.目录匹配 /aaa/bbb/* ----最多的
/user/*:访问前台的资源进入此过滤器
/admin/*:访问后台的资源时执行此过滤器
3.扩展名匹配 *.abc *.jsp
注意:url-pattern可以使用servlet-name替代,也可以混用
访问方式(了解)
dispatcher有以下四个方式(值)
REQUEST:默认值,代表直接访问某个资源时执行filter
FORWARD:转发时才执行filter
INCLUDE: 包含资源时执行filter
ERROR:发生错误时 进行跳转是执行filter
Filter的作用
过滤器Filter的作用大概有以下三点:
1.公共代码的提取
2.可以对request和response中的方法进行增强(装饰者模式/动态代理)
3.进行权限控制
类加载器ClassLoader
简介
类加载器被用于加载字节码文件(.class)
类加载器的种类
类加载器有三种,不同类加载器加载不同的类。
- BootStrap:引导类加载器:加载都是最基础的文件
- ExtClassLoader:扩展类加载器:加载都是基础的文件
- AppClassLoader:应用类加载器:三方jar包和自己编写java文件
获得类加载器
// 获得Demo字节码文件的类加载器
Class clazz = Demo.class;// 获得Demo的字节码对象
ClassLoader classLoader = clazz.getClassLoader();// 获得类加载器
// getResource的参数路径相对classes(src)
// 获得classes(src)下的任何的资源
// jdbc.properties位于src目录下
String path = classLoader.getResource("jdbc.properties").getPath();
System.out.println(path);
注解Annotation
什么是注解
Annotation注解,是一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举在同一个层次。与注释相比较而言,注释是给开发人员阅读的,而注解是给jvm的编译提供信息的。
关于配置文件与注解开发的优缺点:
注解优点:开发效率高 成本低
注解缺点:耦合性大 并且不利于后期维护
注解的作用
1、编译检查:通过给代码标识注解,让编译器能够实现基本的编译检查,如@Override。
2、代码分析:通过给代码标识注解,对代码进行分析,从而达到取代xml的目的。
3、编写文档:通过给代码标识注解,辅助生成帮助文档对应的内容。
jdk5提供的注解
经常使用的是以下三种:
@Override:告知编译器此方法是覆盖父类的
@Deprecated:标注过时
@SuppressWarnings:压制警告
不同的注解只能在不同的位置使用(方法上、字段上、类上),由元注解标识作用对象
元注解
元注解是指注解的注解,包括@Retention @Target @Document @Inherited四种。
1.@Retention: 定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
首先要明确生命周期长度 SOURCE < CLASS < RUNTIME,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
2.@Target:定义注解的作用目标
源码为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
3.@Document:说明该注解将被包含在javadoc中
4.@Inherited:说明子类可以继承父类中的该注解
自定义注解(了解)
根据实际需求,编写使用并解析(通过反射机制)注解。
编写注解
关键字:@interface
注解的属性:
语法:返回值名称();
注意:如果属性的名字是value,并且注解的属性值有一个那么在使用注解时可以省略value
注解属性类型只能是以下几种
1.基本类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型
使用注解
在类/方法/字段 上面是@XXX(......)
解析注解
要想解析使用了注解的类,那么该注解的Retention必须设置成Runtime
注解解析的实质:从注解中解析出属性值
字节码对象存在于获得注解相关的方法
isAnnotationPresent(Class<? extends Annotation> annotationClass):判断该字节码对象身上是否使用该注解了
getAnnotation(Class<A> annotationClass):获得该字节码对象身上的注解对象
代理Proxy
什么是代理
简单打个比方趴~
目标对象/被代理对象 ------ 房主:真正的租房的方法
代理对象 ------- 黑中介:有租房子的方法(调用房主的租房的方法)
执行代理对象方法的对象 ---- 租房的人
流程:我们要租房----->中介(租房的方法)------>房主(租房的方法)
抽象:调用对象----->代理对象------>目标对象
而动态代理就是不用手动编写一个代理对象,不需要一一编写与目标对象相同的方法,这个过程,在运行时的内存中动态生成代理对象。------字节码对象级别的代理对象
动态代理的API
在jdk的API中存在一个Proxy中存在一个生成动态代理的的方法——newProxyInstance
static Object | newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) |
返回值:Object就是代理对象
参数:loader:代表与目标对象相同的类加载器-------目标对象.getClass().getClassLoader()
interfaces:代表与目标对象实现的所有的接口字节码对象数组
h:具体的代理的操作,InvocationHandler接口
注意:JDK的Proxy方式实现的动态代理,目标对象必须有接口,没有接口不能实现jdk版动态代理
实例
public interface TargetInterface {
public void method1();
public String method2();
public int method3(int x);
}
public class Target implements TargetInterface{
@Override
public void method1() {
System.out.println("method1 running...");
}
@Override
public String method2() {
System.out.println("method2 running...");
return "method2";
}
@Override
public int method3(int x) {
return x;
}
}
public class ProxyTest {
@Test// JUnit测试注解
public void test1(){
//获得动态的代理对象----在运行时 在内存中动态的为Target创建一个虚拟的代理对象
//objProxy是代理对象 根据参数确定到底是谁的代理对象
TargetInterface objProxy = (TargetInterface) Proxy.newProxyInstance(
Target.class.getClassLoader(), //与目标对象相同的类加载器
new Class[]{TargetInterface.class},
new InvocationHandler() {
//invoke 代表的是执行代理对象的方法
@Override
//method:代表目标对象的方法字节码对象
//args:代表目标对象的响应的方法的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("目标方法前的逻辑");
//执行目标对象的方法
Object invoke = method.invoke(new Target(), args);
System.out.println("目标方法后的逻辑");
return invoke;
}
}
);
objProxy.method1();
String method2 = objProxy.method2();
System.out.println(method2);
}
}
这个阶段的学习暂时告一段落,至于下一阶段的学习emmm
我是小昶,我们开学后见~~~