JavaSE学习总结(十六)—— 泛型与泛型应用
一、泛型概要
泛型(Generic)的本质是类型参数化,通俗的说就是用一个占位符来表示类型,这个类型可以是String,Integer等不确定的类型,表明可接受的类型。
泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。
1.1、为什么需要泛型
在数据结构中有一种结构叫:栈,它的特点是:先进后出,后进先出
如:放衣服的箱子,糖葫芦
现在来模拟一个栈的数据结构
1.1.1、版本一(强类型)
- package com.nf.math;
- public class ObjUtil {
- public static void main(String[] args) {
- Stack stack=new Stack();
- stack.push(11);
- stack.push(22);
- stack.push(55);
- int data=stack.pop();
- System.out.println(data);
- System.out.println(stack.pop());
- System.out.println(stack.pop());
- }
- }
- class Stack{
- //用于存放数据的数组
- private int[] data=new int[10];
- //当前下标
- private int i=0;
- //进栈
- public void push(int obj){
- data[i++]=obj;
- }
- //出栈
- public int pop(){
- return data[--i];
- }
- }
结果:
- 55
- 22
- 11
缺点是不通用
1.1.2、版本二(Object弱类型)
版本一有明显的缺点,只允许存放int类型的数据,如果需要其它类型的数据怎么办法?
有人提议重新创建不同类型的栈,这样不好,因为如果需要10种不同类型的栈,则需定义10个,维护也麻烦。
使用Object也许可以解决问题,代码如下:
- package com.nf.math;
- public class ObjUtil {
- public static void main(String[] args) {
- Stack stack=new Stack();
- stack.push(1.1);
- stack.push(2.2);
- stack.push(5.5);
- double data=(double)stack.pop();
- System.out.println(data);
- System.out.println(stack.pop());
- System.out.println(stack.pop());
- }
- }
- class Stack{
- //用于存放数据的数组
- private Object[] data=new Object[10];
- //当前下标
- private int i=0;
- //进栈
- public void push(Object obj){
- data[i++]=obj;
- }
- //出栈
- public Object pop(){
- return data[--i];
- }
- }
结果:
- 5.5
- 2.2
- 1.1
缺点是安全隐患(类型转换)
1.1.3、版本三(泛型)
版本二中存在类型的强制转换,如果转换的类型不匹配则会引起运行时异常,存在安全隐患,使用泛型可以解决该问题:
- package com.nf.math;
- public class ObjUtil {
- public static void main(String[] args) {
- Stack<Double> stack=new Stack<Double>();
- stack.push(1.1);
- stack.push(2.2);
- stack.push(5.5);
- double data=stack.pop(); //不需要拆箱,没有类型转换
- System.out.println(data);
- System.out.println(stack.pop());
- System.out.println(stack.pop());
- }
- }
- class Stack<T>{
- //用于存放数据的数组
- private T[] data=(T[])(new Object[10]);
- //当前下标
- private int i=0;
- //进栈
- public void push(T obj){
- data[i++]=obj;
- }
- //出栈
- public T pop(){
- return data[--i];
- }
- }
结果:
- 5.5
- 2.2
- 1.1
因为使用了泛型,兼具了版本一与版本二的优点,没有类型转换,没有安全隐患,可以适用多种不同的数据类型。
java不支持泛型数组,List或ArrayList具有泛型数组的功能。
1.2、泛型的优点
没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。
1、提高程序的安全性和可靠性
使用类型更安全,指定具体类型后,Java编译器会对错误的类型在编译时被捕获,而不是在运行时当作ClassCastException展示出来,从而提高程序的安全性和可靠性
2、消除强制类型转换
例如在集合里使用泛型后,从集合里取出对象后就不需要再进行强制类型转换了,这样使编写程序变得更简单,更不容易出错
3、提高代码重用率
在一个类里要对不同结构类型的对象进行操作时,有的对象成员和方法的逻辑都是一样的,就是类型不一样,就有可能会造成不必要的代码重复,通过使用泛型,只需要一个Java类就可以表示不同类型的对象,从而可以大大提高代码的重用率
1.3、泛型规则
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
- Stack<Double> stack=new Stack<Double>();
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
- Stack<Integer> stack2=stack; //错误
3、泛型的类型参数可以有多个。
- class Stack<T,E,K,M,X>{
- }
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
泛型约束,约束T的类型只能是superclass的子类型
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(“java.lang.String”);
1.4、Java中方法的参数
java中方法参数传递的都是值,与C#区别很大,没有ref与out。
java中数据类型分为基本数据类型和引用数据类型。
- 基本数据类型
- 整型:byte,short,int,long
- 浮点型:float,double
- 字符型:char
- 布尔型:boolean
- 引用数据类型
- 数组
- 类
- 接口
方法的参数分为实际参数,和形式参数。
- 形式参数:定义方法时写的参数。
- 实际参数:调用方法时写的具体数值。
1.4.1、基本数据类型
- package com.nf.math;
- public class ObjUtil {
- public static void main(String[] args) {
- Util util=new Util();
- int n1=100,n2=200;
- util.Swap(n1, n2); //副本
- System.out.println("n1="+n1+",n2="+n2);
- }
- }
- class Util
- {
- public void Swap(int n1, int n2) {
- int temp = n1;
- n1 = n2;
- n2 = temp;
- }
- }
结果:
- n1=100,n2=200
从上面的结果可以看出n1与n2在调用交换方法后并没有实质交换,是因为形参是n1与n2的副本。
1.4.2、引用类型
- package com.nf.math;
- public class ObjUtil {
- public static void main(String[] args) {
- Util util=new Util();
- String n1="100",n2="200";
- util.Swap(n1, n2); //形参是n1的引用副本
- System.out.println("n1="+n1+",n2="+n2);
- }
- }
- class Util
- {
- public void Swap(String n1, String n2) {
- String temp = n1;
- n1 = n2;
- n2 = temp;
- }
- }
结果:
- n1=100,n2=200
依然没有交互
String对象做为参数传递时,走的依然是引用传递,只不过String这个类比较特殊。
String对象一旦创建,内容不可更改。每一次内容的更改都是重现创建出来的新对象。
1.4.3、结论
- 值传递的时候,将实参的值,copy一份给形参。
- 引用传递的时候,将实参的地址值,copy一份给形参。
也就是说,不管是值传递还是引用传递,形参拿到的仅仅是实参的副本,而不是实参本身。
二、自定义泛型类
示例:
- package com.nf.math;
- public class BoxTest {
- public static void main(String[] args) {
- Box<Integer> boxInt = new Box<Integer>();
- boxInt.setAttr(5);
- System.out.println(boxInt.getAttr() + 1);
- }
- }
- class Box<T> {
- private T attr;
- public T getAttr() {
- return this.attr;
- }
- public void setAttr(T attr) {
- this.attr = attr;
- }
- }
结果:
6
三、自定义泛型方法
在自定义泛型类中,整个类都可以使用类型占位T,有时候只需要局部用到则可以定义泛型方法
定义泛型方法,语法如下:
- [访问修饰符] <泛型列表> 返回值 方法名(参数列表) {
- //方法体;
- }
示例:
- package com.nf.math;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- public class BoxTest {
- public static void main(String[] args) {
- Box<Integer> boxInt = new Box<Integer>();
- boxInt.setAttr(5);
- System.out.println(boxInt.getAttr() + 1);
- ReflectUtil.getMethods(Box.class);
- }
- }
- class Box<T> {
- private T attr;
- public T getAttr() {
- return this.attr;
- }
- public void setAttr(T attr) {
- this.attr = attr;
- }
- }
- class ReflectUtil
- {
- public static <T> void getMethods(Class<T> type){
- Method[] methods=type.getMethods();
- System.out.println(type.getName()+":");
- for (Method method : methods) {
- System.out.println(Modifier.toString(method.getModifiers())+" "+method.getReturnType()+" "+method.getName()+"()");
- }
- }
- }
结果:
说明:
1)在泛型列表中声明的泛型,可用于该方法的返回值类型声明、参数类型声明和方法代码中的局部变量的类型声明
2)类中其他方法不能使用当前方法声明的泛型
3)使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型;泛型方法除了定义不同,调用就像普通方法一样。
注意:是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。
四、通配符与泛型约束
4.1、类型通配符
类型通配符一般是使用 ? 代替具体的类型实参。
- package com.nf.math;
- public class BeanTest {
- public static void main(String[] args) {
- // 同一种泛型可以对应多个版本(因为参数类型是不确定的)
- // 不同版本的泛型类实例是不兼容的。
- Bean<String> bean1 = new Bean<String>();
- Bean<Integer> bean2 = new Bean<Integer>();
- System.out.println(bean1.getClass().getName()); // 类型
- System.out.println(bean2.getClass().getName());
- Bean<Number> bean3 = bean1;
- }
- }
- class Bean<T> {
- private T var;
- public T getVar() {
- return var;
- }
- public void setVar(T var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
运行结果:
示例
- package com.nf.math;
- public class BeanTest {
- public static void main(String[] args) {
- // 同一种泛型可以对应多个版本(因为参数类型是不确定的)
- // 不同版本的泛型类实例是不兼容的。
- Bean<String> bean1 = new Bean<String>();
- bean1.setVar("one");
- Bean<Integer> bean2 = new Bean<Integer>();
- bean2.setVar(2);
- System.out.println(bean1.getClass().getName()); // 类型
- System.out.println(bean2.getClass().getName());
- Bean<?> bean3 = bean1;
- Show(bean1);
- //Show(bean2);错误
- Display(bean1);
- Display(bean2);
- }
- public static void Show(Bean<String> p){
- System.out.println("内容是:"+p.getVar());
- }
- public static void Display(Bean<?> p){
- System.out.println("内容是:"+p);
- }
- }
- class Bean<T> {
- private T var;
- public T getVar() {
- return var;
- }
- public void setVar(T var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
结果:
- com.nf.math.Bean
- com.nf.math.Bean
- 内容是:one
- 内容是:one
- 内容是:2
示例:
- class Info<T>{
- private T var ; // 定义泛型变量
- public void setVar(T var){
- this.var = var ;
- }
- public T getVar(){
- return this.var ;
- }
- public String toString(){ // 直接打印
- return this.var.toString() ;
- }
- };
- public class GenericsDemo{
- public static void main(String args[]){
- Info<String> i = new Info<String>() ; // 使用String为泛型类型
- i.setVar("it") ; // 设置内容
- fun(i) ;
- }
- public static void fun(Info<?> temp){ // 可以接收任意的泛型对象
- System.out.println("内容:" + temp) ;
- }
- };
4.2、 上界
4.2.1、通配符上界
类型通配符上限通过形如Stack<? extends Number>形式定义
- class Info<T>{
- private T var ; // 定义泛型变量
- public void setVar(T var){
- this.var = var ;
- }
- public T getVar(){
- return this.var ;
- }
- public String toString(){ // 直接打印
- return this.var.toString() ;
- }
- };
- public class GenericsDemo17{
- public static void main(String args[]){
- Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象
- Info<Float> i2 = new Info<Float>() ; // 声明Float的泛型对象
- i1.setVar(30) ; // 设置整数,自动装箱
- i2.setVar(30.1f) ; // 设置小数,自动装箱
- fun(i1) ;
- fun(i2) ;
- }
- public static void fun(Info<? extends Number> temp){ // 只能接收Number及其Number的子类
- System.out.print(temp + "、") ;
- }
- };
示例
- package com.nf.math;
- public class BeanTest {
- public static void main(String[] args) {
- Bean<String> bean1 = new Bean<String>();
- bean1.setVar("one");
- //public final class Integer extends Number implements Comparable<Integer> {
- Bean<Integer> bean2 = new Bean<Integer>();
- bean2.setVar(2);
- Bean<Number> bean3 = new Bean<Number>();
- bean3.setVar(3);
- //Display(bean1); 错误,原因是T必须继承Number或就是Number类型
- Display(bean2);
- Display(bean3);
- }
- public static void Display(Bean<? extends Number> p){
- System.out.println("内容是:"+p);
- }
- }
- class Bean<T> {
- private T var;
- public T getVar() {
- return var;
- }
- public void setVar(T var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
结果
- 内容是:2
- 内容是:3
4.2.2、占位符上界
- package com.nf.math;
- public class BeanTest {
- public static void main(String[] args) {
- Bean<String> bean1 = new Bean<String>(); //错误,因为T有上界,要求是Number或Number的子类
- //public final class Integer extends Number implements Comparable<Integer>
- Bean<Integer> bean2 = new Bean<Integer>();
- Bean<Number> bean3 = new Bean<Number>();
- }
- }
- class Bean<T extends Number> { //T必须继承Number或就是Number
- private T var;
- public T getVar() {
- return var;
- }
- public void setVar(T var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
4.2.3、多种限制
- class C<T extends Comparable<? super T> & Serializable>
我们来分析以下这句,T extends Comparable这个是对上限的限制,Comparable< super T>这个是下限的限制,Serializable是第2个上限。一个指定的类型参数可以具有一个或多个上限。具有多重限制的类型参数可以用于访问它的每个限制的方法和域。
- class Bean<T extends Number & Serializable>
4.3、下界
4.3.1、通配符下界
类型通配符下限为Stack<? super Number>形式,其含义与类型通配符上限正好相反
- class Info<T>{
- private T var ; // 定义泛型变量
- public void setVar(T var){
- this.var = var ;
- }
- public T getVar(){
- return this.var ;
- }
- public String toString(){ // 直接打印
- return this.var.toString() ;
- }
- };
- public class GenericsDemo21{
- public static void main(String args[]){
- Info<String> i1 = new Info<String>() ; // 声明String的泛型对象
- Info<Object> i2 = new Info<Object>() ; // 声明Object的泛型对象
- i1.setVar("hello") ;
- i2.setVar(new Object()) ;
- fun(i1) ;
- fun(i2) ;
- }
- public static void fun(Info<? super String> temp){ // 只能接收String或Object类型的泛型
- System.out.print(temp + "、") ;
- }
- };
示例:
- package com.nf.math;
- import java.io.Serializable;
- public class BeanTest {
- public static void main(String[] args) {
- Bean<String> bean1 = new Bean<String>();
- bean1.setVar("one");
- //public abstract class Number implements java.io.Serializable
- Bean<Integer> bean2 = new Bean<Integer>();
- bean2.setVar(2);
- Bean<Number> bean3 = new Bean<Number>();
- bean3.setVar(3);
- Bean<Object> bean4 = new Bean<Object>();
- bean4.setVar(4);
- Bean<Serializable> bean5 = new Bean<Serializable>();
- bean5.setVar("5");
- //Display(bean1); //错误
- //Display(bean2); //错误
- Display(bean3);
- Display(bean4);
- Display(bean5);
- }
- //?必是Number或Number的父类,Object,Serializable,Number
- public static void Display(Bean<? super Number> p){
- System.out.println("内容是:"+p);
- }
- }
- class Bean<T> {
- private T var;
- public T getVar() {
- return var;
- }
- public void setVar(T var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
结果:
- 内容是:3
- 内容是:4
- 内容是:5
4.3.2、占位符下界
没有,不存在…
五、类型擦除
5.1、类型擦除
Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这个过程就称为类型擦除。如在代码中定义的List<Object>和List<String>等类型,在编译之后都会变成List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。类型擦除也是Java的泛型实现方式与C++模板机制实现方式之间的重要区别。
Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类型在编译后都会被清除掉。
Java在泛型设计上是一种“伪泛型”,存在着泛型擦除。
类型擦除是Java中泛型的实现方式。泛型是在编译器这个层次来实现的。在Java 源代码中声明的泛型类型信息,在编译过程中会被擦除,只保留不带类型参数的形式。被擦除的类型信息包括泛型类型和泛型方法声明时的形式类型参数,以及参数化类型中的实际类型信息。经过类型擦除之后,包含泛型类型的代码被转换成不包含泛型类型的代码,相当于回到了泛型被引入之前的形式,Java虚拟机在运行字节代码时并不知道泛型类型的存在。
定义好的泛型类:
- public class ObjectHolder<T> {
- private T obj;
- public T getObject() {
- return obj;
- }
- public void setObject(T obj) {
- this.obj = obj;
- }
- }
被转译后:
以上面代码中的ObjectHolder泛型类为例,经过类型擦除后,由于形式类型参数T没有上界,T的所有出现将被替换成Object类型
- public class ObjectHolder {
- private Object obj;
- public Object getObject() {
- return obj;
- }
- public void setObject(Object obj) {
- this.obj = obj;
- }
- }
另外使用ObjectHolder类的代码也要进行处理,如下列代码所示:
- ObjectHolder<String> holder = new ObjectHolder<String>();
- holder.setObject("Hello");
- String str = holder.getObject();
在类型擦除后,ObjectHolder类中的getObject方法的返冋值类型实际上是 Object类型,因此需要添加强制类型转换把getObject方法的返回值转换成String类型。 这些类型转换操作由编译器自动添加。由于编译器已经确保不允许使用除String类的对象之外的其他对象调用setObject方法,因此这个强制类型转换操作始终是合法的,如下列代码所示:
- ObjectHolder holder = new ObjectHolder();
- holder.setObject("Hello");
- String str = (String)holder.getObject();
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除
示例:
- package com.nf.math;
- public class BeanTest {
- public static void main(String[] args) {
- Bean<Integer> bean1=new Bean<Integer>();
- Bean<String> bean2=new Bean<String>();
- System.out.println(bean1.getClass().getName());
- System.out.println(bean2.getClass().getName());
- }
- }
- class Bean<T> {
- private T var;
- public T getVar() {
- return var;
- }
- public void setVar(T var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
结果:
- com.nf.math.Bean
- com.nf.math.Bean
在JVM中的 Class 都是com.nf.math.Bean,泛型信息被擦除了。
5.2、泛型转译
示例:
- package com.nf.math;
- import java.lang.reflect.Field;
- public class BeanTest {
- public static void main(String[] args) throws Exception {
- Bean<Integer> bean1=new Bean<Integer>();
- Bean<String> bean2=new Bean<String>();
- //获得Bean中的字段var
- Field clazz=bean1.getClass().getDeclaredField("var");
- clazz.setAccessible(true);
- clazz.set(bean1, "abc");
- //取字段var的类型
- System.out.println(clazz.getType().getSimpleName());
- System.out.println(bean1.getVar());
- }
- }
- class Bean<T> {
- private T var;
- public T getVar() {
- return var;
- }
- public void setVar(T var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
因为Bean没有上界,T被转译成Object,生成如下代码:
- class BeanCopy {
- private Object var;
- public Object getVar() {
- return var;
- }
- public void setVar(Object var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
运行结果:
- Object
- abc
泛型类被类型擦除后,相应的类型就被替换成 Object 类型呢?,不一定,如果有上界,则被替换成上界:
- package com.nf.math;
- import java.lang.reflect.Field;
- public class BeanTest {
- public static void main(String[] args) throws Exception {
- Bean<Integer> bean1=new Bean<Integer>();
- Bean<Number> bean2=new Bean<Number>();
- //获得Bean中的字段var
- Field clazz=bean1.getClass().getDeclaredField("var");
- //查看运行时字段var的类型
- System.out.println(clazz.getType().getSimpleName());
- }
- }
- class Bean<T extends Number> { //设置上界
- private T var;
- public T getVar() {
- return var;
- }
- public void setVar(T var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
运行结果:
- Number
类型被转译成:
- class Bean{
- private Number var;
- public Number getVar() {
- return var;
- }
- public void setVar(Number var) {
- this.var = var;
- }
- @Override
- public String toString() {
- return var.toString();
- }
- }
六、泛型应用
6.1、泛型与反射简化JDBCUtils工具类示例
参考:https://commons.apache.org/proper/commons-dbutils/
已经写好的工具类:
- package com.zhangguo.utils;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.ResultSetMetaData;
- import java.sql.SQLException;
- import java.sql.Statement;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- public class JDBCUtils {
- public static String DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
- public static String URL = "jdbc:sqlserver://localhost:1433;databasename=pubs";
- public static String USER_NAME = "sa";
- public static String PASSWORD = "sa";
- static {
- try {
- Class.forName(DRIVER);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- private JDBCUtils() {
- }
- /**
- * Get connection
- *
- * @return
- */
- public static Connection getconnnection() {
- Connection con = null;
- try {
- con = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return con;
- }
- /**
- * Close connection
- *
- * @param rs
- * @param st
- * @param con
- */
- public static void close(ResultSet rs, Statement st, Connection con) {
- try {
- try {
- if (rs != null) {
- rs.close();
- }
- } finally {
- try {
- if (st != null) {
- st.close();
- }
- } finally {
- if (con != null)
- con.close();
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- /**
- * Close connection
- *
- * @param rs
- */
- public static void close(ResultSet rs) {
- Statement st = null;
- Connection con = null;
- try {
- try {
- if (rs != null) {
- st = rs.getStatement();
- rs.close();
- }
- } finally {
- try {
- if (st != null) {
- con = st.getConnection();
- st.close();
- }
- } finally {
- if (con != null) {
- con.close();
- }
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- /**
- * Close connection
- *
- * @param st
- * @param con
- */
- public static void close(Statement st, Connection con) {
- try {
- try {
- if (st != null) {
- st.close();
- }
- } finally {
- if (con != null)
- con.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- /**
- * insert/update/delete
- *
- * @param sql
- * @param args
- * @return
- */
- public static int update(String sql, Object... args) {
- int result = 0;
- Connection con = getconnnection();
- PreparedStatement ps = null;
- try {
- ps = con.prepareStatement(sql);
- if (args != null) {
- for (int i = 0; i < args.length; i++) {
- ps.setObject((i + 1), args[i]);
- }
- }
- result = ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- close(ps, con);
- }
- return result;
- }
- /**
- * query, because need to manually close the resource, so not recommended
- * for use it
- *
- * @param sql
- * @param args
- * @return ResultSet
- */
- @Deprecated
- public static ResultSet query(String sql, Object... args) {
- ResultSet result = null;
- Connection con = getconnnection();
- PreparedStatement ps = null;
- try {
- ps = con.prepareStatement(sql);
- if (args != null) {
- for (int i = 0; i < args.length; i++) {
- ps.setObject((i + 1), args[i]);
- }
- }
- result = ps.executeQuery();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return result;
- }
- /**
- * Query a single record
- *
- * @param sql
- * @param args
- * @return Map<String,Object>
- */
- public static Map<String, Object> queryForMap(String sql, Object... args) {
- Map<String, Object> result = new HashMap<String, Object>();
- List<Map<String, Object>> list = queryForList(sql, args);
- if (list.size() > 0) {
- result = list.get(0);
- }
- return result;
- }
- /**
- * Query a single record
- *
- * @param sql
- * @param args
- * @return <T>
- */
- public static <T> T queryForObject(String sql, Class<T> clz, Object... args) {
- T result = null;
- List<T> list = queryForList(sql, clz, args);
- if (list.size() > 0) {
- result = list.get(0);
- }
- return result;
- }
- /**
- * Query a single record
- *
- * @param sql
- * @param args
- * @return List<Map<String,Object>>
- */
- public static List<Map<String, Object>> queryForList(String sql, Object... args) {
- List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
- Connection con = null;
- ResultSet rs = null;
- PreparedStatement ps = null;
- try {
- con = getconnnection();
- ps = con.prepareStatement(sql);
- if (args != null) {
- for (int i = 0; i < args.length; i++) {
- ps.setObject((i + 1), args[i]);
- }
- }
- rs = ps.executeQuery();
- ResultSetMetaData rsmd = rs.getMetaData();
- int columnCount = rsmd.getColumnCount();
- while (rs.next()) {
- Map<String, Object> map = new HashMap<String, Object>();
- for (int i = 1; i <= columnCount; i++) {
- map.put(rsmd.getColumnLabel(i), rs.getObject(i));
- }
- result.add(map);
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- close(rs, ps, con);
- }
- return result;
- }
- /**
- * Query a single record
- *
- * @param sql
- * @param args
- * @return List<T>
- */
- public static <T> List<T> queryForList(String sql, Class<T> clz, Object... args) {
- List<T> result = new ArrayList<T>();
- Connection con = null;
- PreparedStatement ps = null;
- ResultSet rs = null;
- try {
- con = getconnnection();
- ps = con.prepareStatement(sql);
- if (args != null) {
- for (int i = 0; i < args.length; i++) {
- ps.setObject((i + 1), args[i]);
- }
- }
- rs = ps.executeQuery();
- ResultSetMetaData rsmd = rs.getMetaData();
- int columnCount = rsmd.getColumnCount();
- while (rs.next()) {
- T obj = clz.newInstance();
- for (int i = 1; i <= columnCount; i++) {
- String columnName = rsmd.getColumnName(i);
- String methodName = "set" + columnName.substring(0, 1).toUpperCase()
- + columnName.substring(1, columnName.length());
- Method method[] = clz.getMethods();
- for (Method meth : method) {
- if (methodName.equals(meth.getName())) {
- meth.invoke(obj, rs.getObject(i));
- }
- }
- }
- result.add(obj);
- }
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- } finally {
- close(rs, ps, con);
- }
- return result;
- }
- }
View Code
数据库:
- CREATE TABLE `student` (
- `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
- `name` varchar(50) DEFAULT NULL COMMENT '姓名',
- `sex` varchar(20) DEFAULT NULL,
- `cno` varchar(50) DEFAULT NULL COMMENT '班级',
- `addr` varchar(50) DEFAULT NULL COMMENT '籍贯',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
示例:
- package com.zhangguo.utils;
- import java.util.List;
- public class JDBCUtilsTest {
- public static void main(String[] args) {
- List<Student> students = JDBCUtils.queryForList("select * from student where id<=?", Student.class, 10);
- for (Student student : students) {
- System.out.println(student);
- }
- }
- }
- /** 学生 */
- class Student {
- private int id;
- private String name;
- private String sex;
- private String cno;
- private String addr;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public String getCno() {
- return cno;
- }
- public void setCno(String cno) {
- this.cno = cno;
- }
- public String getAddr() {
- return addr;
- }
- public void setAddr(String addr) {
- this.addr = addr;
- }
- @Override
- public String toString() {
- return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", cno=" + cno + ", addr=" + addr + "]";
- }
- }
结果:
6.2、实现泛型与反射简化JDBCUtils工具类
数据库与表的元数据就是用于描述数据库或表的信息,如表的字段(长度,类型,注释),主键,外键,约束等信息,表中的数据本来是描述客观事物的。
6.2.1、获得表的元信息方法一
示例:
- /**
- * 根据数据库的连接参数,获取指定表的基本信息:字段名、字段类型、字段注释
- * 表名
- * @return Map集合
- */
- public static List getTableInfo(String table) {
- List result = new ArrayList();
- Connection conn = null;
- DatabaseMetaData dbmd = null;
- try {
- conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
- dbmd = conn.getMetaData();
- ResultSet resultSet = dbmd.getTables(null, "%", table, new String[] { "TABLE" });
- while (resultSet.next()) {
- String tableName = resultSet.getString("TABLE_NAME");
- System.out.println(tableName);
- if (tableName.equals(table)) {
- ResultSet rs = conn.getMetaData().getColumns(null, getSchema(conn), tableName.toUpperCase(), "%");
- while (rs.next()) {
- // System.out.println("字段名:"+rs.getString("COLUMN_NAME")+"--字段注释:"+rs.getString("REMARKS")+"--字段数据类型:"+rs.getString("TYPE_NAME"));
- Map map = new HashMap();
- String colName = rs.getString("COLUMN_NAME");
- map.put("code", colName);
- String remarks = rs.getString("REMARKS");
- if (remarks == null || remarks.equals("")) {
- remarks = colName;
- }
- map.put("name", remarks);
- String dbType = rs.getString("TYPE_NAME");
- map.put("dbType", dbType);
- map.put("valueType", changeDbType(dbType));
- result.add(map);
- }
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- return result;
- }
- private static String changeDbType(String dbType) {
- dbType = dbType.toUpperCase();
- switch (dbType) {
- case "VARCHAR":
- case "VARCHAR2":
- case "CHAR":
- return "1";
- case "NUMBER":
- case "DECIMAL":
- return "4";
- case "INT":
- case "SMALLINT":
- case "INTEGER":
- return "2";
- case "BIGINT":
- return "6";
- case "DATETIME":
- case "TIMESTAMP":
- case "DATE":
- return "7";
- default:
- return "1";
- }
- }
- // 其他数据库不需要这个方法 oracle和db2需要
- private static String getSchema(Connection conn) throws Exception {
- String schema;
- schema = conn.getMetaData().getUserName();
- if ((schema == null) || (schema.length() == 0)) {
- throw new Exception("ORACLE数据库模式不允许为空");
- }
- return schema.toUpperCase().toString();
- }
结果:
- persons
- student
- [{code=id, valueType=2, name=编号, dbType=INT}, {code=name, valueType=1, name=姓名, dbType=VARCHAR}, {code=sex, valueType=1, name=sex, dbType=VARCHAR}, {code=cno, valueType=1, name=班级, dbType=VARCHAR}, {code=addr, valueType=1, name=籍贯, dbType=VARCHAR}]
View Code
6.2.2、获得表的元信息方法二
代码:
- package com.zhangguo.utils;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.ResultSetMetaData;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
- public class DbUtils {
- public static String DRIVER = "com.mysql.jdbc.Driver";
- public static String URL = "jdbc:mysql://localhost:3306/studentmis?useUnicode=true&characterEncoding=utf8";
- public static String USER_NAME = "mysqluser";
- public static String PASSWORD = "root";
- static {
- try {
- Class.forName(DRIVER);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- public static List<Student> getStudents(String sql, Object... params) throws Exception {
- List<Student> result = new ArrayList<>();
- Connection conn = null;
- PreparedStatement pstm = null;
- conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
- pstm = conn.prepareStatement(sql);
- // 添加参数
- if (params != null) {
- for (int i = 0; i < params.length; i++) {
- pstm.setObject(i + 1, params[i]);
- }
- }
- // 执行查询
- ResultSet rs = pstm.executeQuery();
- //获得表的元数据
- ResultSetMetaData rsmd=pstm.getMetaData();
- //表的列数
- int metaSize=rsmd.getColumnCount();
- for (int i =1; i <=metaSize; i++) {
- System.out.println("列名:"+rsmd.getColumnName(i));
- System.out.println("长度:"+rsmd.getColumnDisplaySize(i));
- System.out.println("类型:"+rsmd.getColumnType(i));
- System.out.println("类型:"+rsmd.getColumnTypeName(i));
- System.out.println("----------");
- }
- while (rs.next()) {
- Student student=new Student();
- student.setAddr(rs.getString("addr"));
- student.setCno(rs.getString("cno"));
- student.setId(rs.getInt("id"));
- student.setName(rs.getString("name"));
- student.setSex(rs.getString("sex"));
- result.add(student);
- }
- CloseConnection(conn, pstm, rs);
- return result;
- }
- public static void CloseConnection(Connection conn, PreparedStatement pstm, ResultSet rs) throws SQLException {
- if (rs != null) {
- rs.close();
- }
- if (pstm != null) {
- pstm.close();
- }
- if (conn != null) {
- conn.close();
- }
- }
- }
测试类:
- package com.zhangguo.utils;
- import java.util.List;
- public class JDBCUtilsTest {
- public static void main(String[] args) throws Exception {
- List<Student> students = JDBCUtils.queryForList("select * from student where id<=?", Student.class, 10);
- for (Student student : students) {
- System.out.println(student);
- }
- System.out.println("-------------------------------------------------------------------");
- List<Student> stus =DbUtils.getStudents("select * from student where id<=?", 5);
- for (Student student : stus) {
- System.out.println(student);
- }
- System.out.println("-------------------------------------------------------------------");
- System.out.println(stus);
- }
- }
- /** 学生 */
- class Student {
- private int id;
- private String name;
- private String sex;
- private String cno;
- private String addr;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public String getCno() {
- return cno;
- }
- public void setCno(String cno) {
- this.cno = cno;
- }
- public String getAddr() {
- return addr;
- }
- public void setAddr(String addr) {
- this.addr = addr;
- }
- @Override
- public String toString() {
- return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", cno=" + cno + ", addr=" + addr + "]";
- }
- }
结果:
- Student [id=1, name=张学友, sex=男, cno=S1SJ90, addr=中国香港]
- Student [id=2, name=黎明, sex=男, cno=S1SJ18, addr=中国上海]
- Student [id=3, name=张慧妹, sex=女, cno=S2SJ19, addr=中国北京]
- Student [id=4, name=张国立, sex=男, cno=S3J37, addr=中国广东]
- Student [id=5, name=张哪啦, sex=女, cno=S3SR96, addr=中国杭州]
- Student [id=6, name=张铁林, sex=男, cno=S2SJ140, addr=中国珠海]
- Student [id=7, name=张国荣, sex=男, cno=S1SJ111, addr=中国香港]
- Student [id=8, name=张果果, sex=女, cno=S3SU198, addr=中国深圳]
- Student [id=10, name=张小军, sex=女, cno=S1SN196, addr=中国斗门]
- -------------------------------------------------------------------
- 列名:id
- 长度:11
- 类型:4
- 类型:INT
- ----------
- 列名:name
- 长度:50
- 类型:12
- 类型:VARCHAR
- ----------
- 列名:sex
- 长度:20
- 类型:12
- 类型:VARCHAR
- ----------
- 列名:cno
- 长度:50
- 类型:12
- 类型:VARCHAR
- ----------
- 列名:addr
- 长度:50
- 类型:12
- 类型:VARCHAR
- ----------
- Student [id=1, name=张学友, sex=男, cno=S1SJ90, addr=中国香港]
- Student [id=2, name=黎明, sex=男, cno=S1SJ18, addr=中国上海]
- Student [id=3, name=张慧妹, sex=女, cno=S2SJ19, addr=中国北京]
- Student [id=4, name=张国立, sex=男, cno=S3J37, addr=中国广东]
- Student [id=5, name=张哪啦, sex=女, cno=S3SR96, addr=中国杭州]
- -------------------------------------------------------------------
- [Student [id=1, name=张学友, sex=男, cno=S1SJ90, addr=中国香港], Student [id=2, name=黎明, sex=男, cno=S1SJ18, addr=中国上海], Student [id=3, name=张慧妹, sex=女, cno=S2SJ19, addr=中国北京], Student [id=4, name=张国立, sex=男, cno=S3J37, addr=中国广东], Student [id=5, name=张哪啦, sex=女, cno=S3SR96, addr=中国杭州]]
6.3、封装DbUtilis工具类
6.3.1.、查询功能
- package com.zhangguo.utilities;
- import java.lang.reflect.Field;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.ResultSetMetaData;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
- public class DbUtils {
- public static String DRIVER = "com.mysql.jdbc.Driver";
- public static String URL = "jdbc:mysql://localhost:3306/studentmis?useUnicode=true&characterEncoding=utf8";
- public static String USER_NAME = "mysqluser";
- public static String PASSWORD = "root";
- static {
- try {
- Class.forName(DRIVER);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- public static <T> List<T> queryList(String sql,Class<T> clazz,Object... params) throws Exception {
- List<T> result = new ArrayList<>();
- Connection conn = null;
- PreparedStatement pstm = null;
- conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
- pstm = conn.prepareStatement(sql);
- // 添加参数
- if (params != null) {
- for (int i = 0; i < params.length; i++) {
- pstm.setObject(i + 1, params[i]);
- }
- }
- // 执行查询
- ResultSet rs = pstm.executeQuery();
- // 获得表的元数据
- ResultSetMetaData rsmd = pstm.getMetaData();
- // 表的列数
- int metaSize = rsmd.getColumnCount();
- while (rs.next()) {
- T entity = clazz.newInstance();
- for (int i = 1; i <= metaSize; i++) {
- //获得当前列的列名
- String columnName=rsmd.getColumnName(i);
- //根据字段名获得实体类中的字段
- Field field=clazz.getDeclaredField(columnName);
- //设置字段可以被访问
- field.setAccessible(true);
- //给实体中的字段赋值
- field.set(entity, rs.getObject(columnName));
- }
- result.add(entity);
- }
- CloseConnection(conn, pstm, rs);
- return result;
- }
- public static void CloseConnection(Connection conn, PreparedStatement pstm, ResultSet rs) throws SQLException {
- if (rs != null) {
- rs.close();
- }
- if (pstm != null) {
- pstm.close();
- }
- if (conn != null) {
- conn.close();
- }
- }
- }
测试:
- package com.zhangguo.utilities;
- import java.util.List;
- public class DbUtilsTest {
- public static void main(String[] args) throws Exception {
- List<Animal> result = DbUtils.queryList("select * from animal where id<?", Animal.class, 5);
- System.out.println(result);
- List<Student> students = DbUtils.queryList("select * from student where id<?", Student.class, 5);
- System.out.println(students);
- }
- }
- /** 动物 */
- class Animal {
- private int id;
- private String name;
- private String color;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getColor() {
- return color;
- }
- public void setColor(String color) {
- this.color = color;
- }
- @Override
- public String toString() {
- return "Animal [id=" + id + ", name=" + name + ", color=" + color + "]";
- }
- }
- /** 学生 */
- class Student { //T只允许是String或String的子类
- private int id;
- private String name;
- private String sex;
- private String cno;
- private String addr;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public String getCno() {
- return cno;
- }
- public void setCno(String cno) {
- this.cno = cno;
- }
- public String getAddr() {
- return addr;
- }
- public void setAddr(String addr) {
- this.addr = addr;
- }
- @Override
- public String toString() {
- return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", cno=" + cno + ", addr=" + addr + "]";
- }
- }
结果:
- [Animal [id=1, name=Dog, color=yellow], Animal [id=2, name=Cat, color=White], Animal [id=3, name=Duck, color=Black]]
- [Student [id=1, name=张学友, sex=男, cno=S1SJ90, addr=中国香港], Student [id=2, name=黎明, sex=男, cno=S1SJ18, addr=中国上海], Student [id=3, name=张慧妹, sex=女, cno=S2SJ19, addr=中国北京], Student [id=4, name=张国立, sex=男, cno=S3J37, addr=中国广东]]
View Code
6.3.2、增删改功能
- package com.zhangguo.utilities;
- import java.lang.reflect.Field;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.ResultSetMetaData;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
- public class DbUtils {
- public static String DRIVER = "com.mysql.jdbc.Driver";
- public static String URL = "jdbc:mysql://localhost:3306/studentmis?useUnicode=true&characterEncoding=utf8";
- public static String USER_NAME = "mysqluser";
- public static String PASSWORD = "root";
- static {
- try {
- Class.forName(DRIVER);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- public static <T> List<T> queryList(String sql, Class<T> clazz, Object... params) throws Exception {
- List<T> result = new ArrayList<>();
- Connection conn = null;
- PreparedStatement pstm = null;
- conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
- pstm = conn.prepareStatement(sql);
- // 添加参数
- if (params != null) {
- for (int i = 0; i < params.length; i++) {
- pstm.setObject(i + 1, params[i]);
- }
- }
- // 执行查询
- ResultSet rs = pstm.executeQuery();
- // 获得表的元数据
- ResultSetMetaData rsmd = pstm.getMetaData();
- // 表的列数
- int metaSize = rsmd.getColumnCount();
- while (rs.next()) {
- T entity = clazz.newInstance();
- for (int i = 1; i <= metaSize; i++) {
- // 获得当前列的列名
- String columnName = rsmd.getColumnName(i);
- // 根据字段名获得实体类中的字段
- Field field = clazz.getDeclaredField(columnName);
- // 设置字段可以被访问
- field.setAccessible(true);
- // 给实体中的字段赋值
- field.set(entity, rs.getObject(columnName));
- }
- result.add(entity);
- }
- CloseConnection(conn, pstm, rs);
- return result;
- }
- public static <T> T queryObject(String sql, Class<T> clazz, Object... params) throws Exception {
- List<T> result = queryList(sql, clazz, params);
- if (result != null && !result.isEmpty()) {
- return result.get(0);
- }
- return null;
- }
- public static int execute(String sql, Object... params) throws Exception {
- int rows = 0;
- Connection conn = null;
- PreparedStatement pstm = null;
- conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
- pstm = conn.prepareStatement(sql);
- // 添加参数
- if (params != null) {
- for (int i = 0; i < params.length; i++) {
- pstm.setObject(i + 1, params[i]);
- }
- }
- // 执行
- rows = pstm.executeUpdate();
- CloseConnection(conn, pstm, null);
- return rows;
- }
- public static void CloseConnection(Connection conn, PreparedStatement pstm, ResultSet rs) throws SQLException {
- if (rs != null) {
- rs.close();
- }
- if (pstm != null) {
- pstm.close();
- }
- if (conn != null) {
- conn.close();
- }
- }
- }
View Code
6.4、JSON返回类型封装
- package com.zhangguo.utils;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * 返回类型封装
- */
- public class R extends HashMap<String, Object> {
- private static final long serialVersionUID = 1L;
- public R() {
- put("code", 0);
- put("msg", "success");
- }
- //错误时
- public static R error() {
- return error(500, "未知异常,请联系管理员");
- }
- public static R error(String msg) {
- return error(500, msg);
- }
- public static R error(int code, String msg) {
- R r = new R();
- r.put("code", code);
- r.put("msg", msg);
- return r;
- }
- //成功时
- public static R ok(String msg) {
- R r = new R();
- r.put("msg", msg);
- return r;
- }
- public static R ok(Map<String, Object> map) {
- R r = new R();
- r.putAll(map);
- return r;
- }
- public static R ok() {
- return new R();
- }
- @Override
- public R put(String key, Object value) {
- super.put(key, value);
- return this;
- }
- }
测试:
- package com.zhangguo.controller;
- import java.util.*;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.zhangguo.utils.DbUtils;
- import com.zhangguo.utils.JsonUtils;
- import com.zhangguo.utils.R;
- @WebServlet("/StudentController")
- public class StudentController extends BaseServlet {
- private static final long serialVersionUID = 1L;
- public void getAllStudent(HttpServletRequest request, HttpServletResponse response) {
- List<Student> students=null;
- try {
- students = DbUtils.queryList("select * from student", Student.class);
- String json = JsonUtils.toJson(students);
- response.getWriter().append(json);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public void getAllStus(HttpServletRequest request, HttpServletResponse response) {
- List<Student> students=null;
- try {
- students = DbUtils.queryList("select * from student", Student.class);
- R r=R.ok().put("data", students).put("time",new Date());
- String json = JsonUtils.toJson(r);
- response.getWriter().append(json);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
运行结果:
jsonUtils:
- package com.zhangguo.utils;
- import java.text.SimpleDateFormat;
- import com.fasterxml.jackson.core.JsonProcessingException;
- import com.fasterxml.jackson.databind.ObjectMapper;
- public class JsonUtils {
- /**
- * 序列化成json
- * */
- public static String toJson(Object obj) {
- // 对象映射器
- ObjectMapper mapper = new ObjectMapper();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd HH:mm:ss");
- mapper.setDateFormat(sdf);
- String result = null;
- // 序列化user对象为json字符串
- try {
- result = mapper.writeValueAsString(obj);
- } catch (JsonProcessingException e) {
- e.printStackTrace();
- }
- return result;
- }
- /**
- * 反序列化成对象
- * */
- public static <T> T toObject(String json,Class<T> valueType) {
- //对象映射器
- ObjectMapper mapper=new ObjectMapper();
- T result=null;
- try {
- result=mapper.readValue(json,valueType);
- }catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
- }
View Code
baseServlet:
- package com.zhangguo.controller;
- import java.io.IOException;
- import java.lang.reflect.Method;
- import javax.servlet.ServletConfig;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class BaseServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- public void init(ServletConfig config) throws ServletException {
- }
- public String commonObject;
- //Write once only once!
- protected void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String action = request.getParameter("act");
- request.setCharacterEncoding("utf-8");
- response.setCharacterEncoding("utf-8");
- response.setContentType("text/html;charset=utf-8");
- if (action != null) {
- try {
- // 在当前Servlet实例中根据action找到方法信息
- Method method = getClass().getDeclaredMethod(action, HttpServletRequest.class,
- HttpServletResponse.class);
- if (method != null) {
- // 在当前实例上调用方法method,指定参数request,response
- method.invoke(this, request, response);
- } else {
- response.getWriter().write("您请求的action不存在");
- }
- } catch (Exception e) {
- response.getWriter().write("调用发生了错误,错误:" + e.getMessage());
- e.printStackTrace();
- }
- } else {
- try {
- response.getWriter().write("请指定参数act");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
View Code
七、视频
https://www.bilibili.com/video/av9219224/
八、作业
7.1、请定义一个泛型类,实现简单的List功能,可变长度的数组,可以实现foreach功能。
- MyList<Integer> list1=new MyList<Integer>();
- list1.add(1);
- list1.add(2);
- list1.add(3);
- foreach(Integer i : list){
- System.out.println(i);
- }
7.2、请定义一个泛型方法,根据指定的类型获得方法中所有的字段、方法信息。
7.3、请使用JDBC+反射+泛型实现一个可返回强类型的方法,如:
指定SQL语句、参数与类型返回一个强类型对象
- List<Student> students = JDBCUtils.queryForList("select * from student where id<=?", Student.class, 10);
- for (Student student : students) {
- System.out.println(student);
- }
View Code
7.4、指定一个数据库,生成数据库下所有的表的实体类文件
7.5、JDBC+反射+泛型实现一个简单的ORM(选作)
- package model;
- import java.util.Date;
- import annotation.Column;
- import annotation.Entity;
- import annotation.Id;
- /**
- * 图书
- */
- @Entity("t_book") //表名
- public class Book {
- /**
- * 图书编号
- */
- @Id("t_isbn")
- private String isbn;
- /**
- * 书名
- */
- @Column("t_name")
- private String name;
- /**
- * 作者
- */
- @Column("t_author")
- private String author;
- /**
- * 出版社
- */
- @Column("t_publishing")
- private String publishing;
- /**
- * 出版时间
- */
- @Column(value = "t_pubdate")
- private Date pubdate;
- /**
- * 价格
- */
- @Column(value = "t_price")
- private double price;
- public String getIsbn() {
- return isbn;
- }
- public void setIsbn(String isbn) {
- this.isbn = isbn;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAuthor() {
- return author;
- }
- public void setAuthor(String author) {
- this.author = author;
- }
- public String getPublishing() {
- return publishing;
- }
- public void setPublishing(String publishing) {
- this.publishing = publishing;
- }
- public Date getPubdate() {
- return pubdate;
- }
- public void setPubdate(Date pubdate) {
- this.pubdate = pubdate;
- }
- public double getPrice() {
- return price;
- }
- public void setPrice(double price) {
- this.price = price;
- }
- @Override
- public String toString() {
- return "书名: " + name + " 图书编号: " + isbn + " 作者: " + author
- + " 出版社: " + publishing + " 出版时间: " + pubdate
- + " 价格: " + price;
- }
- }
View Code
调用:
- package xml;
- import java.io.InputStream;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import model.Book;
- import org.junit.BeforeClass;
- import org.junit.Test;
- import util.DateUtils;
- import dao.GenericDao;
- import dao.JdbcGenericDaoImpl;
- /**
- * 测试泛型DAO的CRUD操作
- */
- public class GenericDaoTest {
- private GenericDao<Book> bookDao = new JdbcGenericDaoImpl<Book>();
- private static InputStream is;
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- is = XmlParserTest.class.getResourceAsStream("/books.xml");
- }
- @Test
- public void testSave() throws Exception {
- List<Book> books = SaxHelper.saxReader(is);
- for (Book book : books) {
- bookDao.save(book);
- }
- }
- @Test
- public void testStudentFindAll1() throws Exception {
- System.out.println("\n-------------更新、删除前,测试查询所有记录--------------------");
- List<Book> books = bookDao.findAllByConditions(null, Book.class);
- for (Book book : books) {
- System.out.println(book);
- }
- }
- @Test
- public void testDelete() throws Exception {
- System.out.println("\n-------------测试删除一条记录--------------------");
- bookDao.delete("9787111349662",Book.class);
- }
- @Test
- public void testGet() throws Exception {
- System.out.println("\n-------------测试查询一条记录--------------------");
- Book book = bookDao.get("9787121025389", Book.class);
- System.out.println(book);
- }
- @Test
- public void testUpdate() throws Exception {
- System.out.println("\n-------------测试修改一条记录--------------------");
- Book book = new Book();
- book.setIsbn("9787121025389");
- book.setName("JAVA面向对象编程");
- book.setAuthor("孙卫琴");
- book.setPublishing("电子工业出版社");
- book.setPubdate(DateUtils.string2Date("yyyy-MM-dd", "2006-07-01"));
- book.setPrice(50.6);
- bookDao.update(book);
- }
- @Test
- public void testStudentFindAll2() throws Exception {
- System.out.println("\n-------------更新、删除前,测试根据条件查询所有记录--------------------");
- Map<String,Object> sqlWhereMap = new HashMap<String, Object>();
- //sqlWhereMap.put("t_isbn", "9787111213826");
- //sqlWhereMap.put("t_name", "Java");
- sqlWhereMap.put("t_publishing", "机械工业出版社");
- //sqlWhereMap.put("t_pubdate", new Date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2007-01-01 12:06:00").getTime()));
- List<Book> books = bookDao.findAllByConditions(null, Book.class);
- for (Book book : books) {
- System.out.println(book);
- }
- }
- }
View Code
参考:
https://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845938.html
https://www.cnblogs.com/lwbqqyumidi/p/3837629.html