Web笔记-基础加强

泛型高级应用
  1. 自定义泛型方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package cn.imeina.web.enhancebasic.generic;
    /**
    * 自定义泛型方法:<T>需提前申明定义,才能使用
    * @author gaopengfei
    *
    */
    public class CustomGenericMethod {
    public <T> T method1(T t){
    return null;
    }
    public <T> void method2(T t){
    }
    }
  1. 自定义泛型类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    package cn.imeina.web.enhancebasic.generic;
    /**
    * 自定义泛型类
    * @author gaopengfei
    *
    * @param <T>
    */
    public class CustomGenericClass<T> {
    public T method1(T t){
    return null;
    }
    public void method2(T t){
    }
    /**
    * 静态泛型方法,必须提前申明定义
    * @param t
    * @return
    */
    public static <T> T method3(T t){
    return null;
    }
    /**
    * 定义多个泛型:多用于map
    * @param k
    * @return
    */
    public static <K,V> V method4(K k){
    return null;
    }
    }
  2. 泛型通配符?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package cn.imeina.web.enhancebasic.generic;
    import java.util.Collection;
    /**
    * 泛型通配符
    * @author gaopengfei
    *
    */
    public class GenericWildcards {
    /**
    * 该方法只能打印泛型为string类型的数组元素
    * @param strr
    */
    public static void print1(Collection<String> strr){
    for (String string : strr) {
    System.out.println(string);
    }
    }
    /**
    * 通配符为了解决print1方法的限制而诞生
    * 使用?通配符是引用类型,但是通配符因为不确定类型所以不能调用和类型有关的方法例如add等方法...
    * @param arr
    */
    public static void print2(Collection<?> arr){
    for (Object object : arr) {
    System.out.println(object);
    }
    }
    }
  3. 泛型的上下限

    1
    2
    类名<? extends 类>对象名:泛型的上限(类及其子类)
    类名<? super 类>对象名:泛型的下限(类及其父类)
  4. 泛型的定义者和泛型的使用者

  • 泛型的定义者:

    1
    2
    ArrayList<E>:类型的形式参数(形参)
    ArrayList<E>:带有泛型的类
  • 泛型的使用者:

    1
    2
    ArrayList<Integer>:类型的实际参数(实参)
    ArrayList<Integer>:参数化的泛型类(ParamerizedType就是这种类型)
    1. 泛型的反射
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      Class<T> clazz;
      public BaseDao() {
      //得到当前类型的带有泛型类型的父类
      //如果是public class UserDaoImpl extends BaseDao<UserInfo> implements UserDao,得到的就是BaseDao<UserInfo>
      Type type = this.getClass().getGenericSuperclass();
      //参数化类的泛型类型
      ParameterizedType pt = (ParameterizedType) type;
      //获取实际类型参数
      Type[] types = pt.getActualTypeArguments();
      clazz = (Class<T>) types[0];
      }

DAO模型

DAO(Data Access Object) 数据访问对象是一个面向对象的数据库接口,数据访问:顾名思义就是与数据库打交道。夹在业务逻辑与数据库资源中间。
在核心J2EE模式中是这样介绍DAO模式的:为了建立一个健壮的J2EE应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个特定的数据存储

传统的DAO模型结构如图所示

但是这样做会发现,因为是操作数据库所以多数DAO接口有着相同的CURD操作。如果每写一个DAO都写4个CURD代码重复率极高,而且对应都Impl实现类也同样做相同都代码,为了解决复用问题精简代码。可以向上抽取

抽取优化
DAO模式是标准的J2EE设计模式之一.开发人员使用这个模式把底层的数据访问操作和上层的商务逻辑分开.一个典型的DAO实现有下列几个组件:

  • 一个DAO工厂类;
  • 一个DAO接口;
  • 一个实现DAO接口的具体类;
  • 数据传递对象(有些时候叫做值对象);

具体的DAO类包含了从特定的数据源访问数据的逻辑。


注解(Annotation)

从JDK5.0开始,Java提供了对元数据(MetaData)对支持,也就是Annotation注解。
Annotation其实就是代码里对特殊标记,用于替代配置文件,传统方式通过配置文件告诉类如何运行,有类注解后开发人员可以通过注解告知类如何运行。
在Java注解中可以通过反射获取类中对注解,以决定如何运行类。

  1. JDK中的三个注解

    1
    2
    3
    @Overrived:覆盖父类方法
    @Deprecated:标识类或方法过时
    @SuppressWarnings:抑制警告
  2. 自定义注解

  • 语法

    1
    2
    3
    4
    public @interface 注解名{
    类型 属性名() [default 值];
    }
    注解的类型必须是基本类型、String、Annotation、Class、Enum、及以上类型的一维数组
  • 使用

    1
    2
    @注解名(属性=值[,属性=值])
    注:默认情况下若无自定义value属性,自定义注解会有默认的一个属性名value

自定义注解及使用
注:自定义注解都属于java.lang.annotation.Annotation类型

  1. 元注解:用于注解上的注解,就上元注解
  • @Retention:用于更改注解的存活范围
    RetentionPolicy value();
    RetentionPolicy是枚举类型,有3个值:SOURCE、CLASS、RUNTIM
  • @Target:用于标识该注解使用的范围
    ElementType[] value();
    ElementType是枚举类型,有10个值:
    TYPE
    FIELD
    METHOD
    PARAMETER
    CONSTRUCTOR,
    LOCAL_VARIABLE,
    ANNOTATION_TYPE,
    PACKAGE,
    TYPE_PARAMETER,
    TYPE_USE
    
    • @Documented:用于标识该注解是否出现在javadoc文档中
  • @Inherited:用于标识该注解若作用于类上是否可以被继承

类的状态

  1. 注解的反射
    java.lang.reflect.AnnotatedEmelent:表示目前正在此 VM 中运行的程序的一个已注释元素。该接口允许反射性地读取注释。由此接口中的方法返回的所有注释都是不可变并且可序列化的。调用者可以修改已赋值数组枚举成员的访问器返回的数组;这不会对其他调用者返回的数组产生任何影响。
    方法摘要:
返回值 方法
T getAnnotation(Class annotationClass):如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
Annotation[] getAnnotations():返回此元素上存在的所有注释。
Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。
boolean sAnnotationPresent(Class<? extends Annotation> annotationClass):如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。

所有已知实现类:AccessibleObject, Class, Constructor, Field, Method, Package

1
2
3
Class.isAnnotationPresent(Ann1.class):判断该类上是否有Ann1注解存在
Field.isAnnotationPresent(Ann1.class):判断该字段上是否有Ann1注解存在
Method.isAnnotationPresent(Ann1.class):判断该方法上是否有Ann1注解存在

注解反射


Servlet3.0注解新特性
Tomcat版本 Servlet版本 JavaEE版本 JDK版本
7.x 3.0 JavaEE6.0 JDK6+
6.x .5 JavaEE5.0 JDK5+

具体Servlet3.0注解使用及属性查看@WebServlet注解即可。
注解的出现可以替换xml复杂的配置,减轻代码量,同时使用注解就等同于使用类硬编码,但是它的优点还是大于缺点。


动态代理

Java的动态代理主要涉及到俩个类

  • java.lang.reflect.Proxy
返回值 方法
static InvocationHandler getInvocationHandler(Object proxy) 返回指定代理实例的调用处理程序
static Class<?> getProxyClass(ClassLoader loader, Class<?>… interfaces) 返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。
static boolean static boolean isProxyClass(Class<?> cl) 当且仅当指定的类通过 getProxyClass 方法或 newProxyInstance 方法动态生成为代理类时,返回 true。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类

  • java.lang.reflect.InvocationHandler
返回值 方法
Object invoke(Object proxy, Method method, Object[] args) 在代理实例上处理方法调用并返回结果。

使用:

1
2
3
4
5
6
创建某一接口 Foo 的代理:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });
或使用以下更简单的方法:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);

动态代理使用
总结:动态代理对象的作用,拦截业务逻辑进行统一管理或控制,实现一种编程思想(AOP面向切面编程)


类加载器
  1. 类加载器的作用就是把存放在磁盘或网络的.class文件加载到JVM虚拟机内存中,并为之生成对应的java.lang.Class对象
  2. JVM在启动时会形成由三个类加载器组成的初始类加载器层次结构。

类加载器结构

  1. 类加载器的父类委托机制
  • BootStrap:爷爷
  • ExtClassLoader:父亲
  • AppClassLoader:儿子

在加载一个.class文件的时候,执行顺序永远是:BootStrap–>ExtClassLoader–>AppClassLoader
子类永远委托父类去查找并加载,父类没有范围内没有找到对应的.class文件则委托儿子寻找加载,若儿子依然没有,则抛出NotClassFoundException异常

类加载器


支付

支付方式
WEB中的支付方式大致分为两种:

  1. 分别接入各大银行的支付API,优点是:安全、无额外的手续费用等,直接与银行进行对接;缺点是:开发工作量大,一旦银行接口有变动就需要修改调整编码
  2. 接入第三方支付服务,第三方与银行进行对接,我们只需要集成第三方提供的API进行引导用户支付。线下定期进行资金结算即可。优点是:快速,工作量小;缺点是安全问题

支付流程

支付流程图
由图可知,Web支付,其实所做的只有两件事:按照第三方规范进行数据组装;验证三方返回数据,更改状态。

如果帮到了你,想打赏支持,喏~