上一篇文章地址: http://www.jianshu.com/p/ef159add53ed
这一章梳理一下整个数据库模块内部协作的流程:
相互关系图中 我特意用两种不同的颜色划分两个不同的功能--黑色和红色部分
黑色部分
模块的工作的第一部分是黑色部分,他的功能较为简单,也就是以autogenerate
模块作为主导,通过 db
模块连接数据库,并且通过查询结果映射生成 dojo
部分可以用来查询的类。也就是:
autogenerate ----->请求连接数据库------>db------->执行查询,并将结果返回-------->autogenerate收到查询结果----------->生成对应的dojo类,这也就是之前文章提到的danmaku.java文件的由来
黑色部分已经在上一篇文章中有例子了,现在重点讲述红色部分的逻辑。
红色部分
不知道大家对于上一篇文章的此处是否还有印象?
Danmaku danmaku = new Danmaku().roomidEqual(45).get();
要获取roomid
为45的弹幕居然就一行就能解决,还不用处理sql查询之后的将对应字段放入类的属性中,是不是感觉很神奇?反正我那时候是觉得听神奇的。
这幕后功臣是Bean
模块,在之前的介绍中也提到他是负责类的存取属性等操作。以下是他的主要类:
package com.angroid.bean;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.json.JSONObject;
import com.angroid.dojo.DojoImpl;
import com.angroid.html.Element;
import com.angroid.web.MultiPartRequest;
public class BeanFactory {
/**
* 为不同类型的对象,选择对应封装操作类
* @param obj
* @return
*/
public static Bean newBean(Object obj){
if (obj instanceof Bean){
return (Bean)obj;
}
if(obj instanceof Map){
return new BeanMap((Map) obj);
}
if(obj instanceof ResultSet){
return new BeanResultSet((ResultSet) obj);
}
if(obj instanceof MultiPartRequest){
return new BeanRequest((MultiPartRequest) obj);
}
if(obj instanceof HttpSession){
return new SessionBean((HttpSession) obj);
}
if(obj instanceof DojoImpl){
return new DojoBean(obj);
}
if (obj instanceof Element){
return new ElementBean((Element)obj);
}
if (obj instanceof JSONObject){
return new BeanJSONObject((JSONObject)obj);
}
return new BeanObject(obj);
}
public static Map toMap(Object obj){
Map r = new HashMap();
Bean b = newBean(r);
b.setAll(obj);
return r;
}
}
这里使用的是设计模式中的工厂模式,需要什么的时候就通过工厂造出来。我们关注BeanObject
这个类,他是实现我们文章开头那一行语句的关键。
package com.angroid.bean;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.angroid.cast.CasterFactory;
/**
* 实现BeanBase接口,普通的java类
* @author Alien
*
*/
public class BeanObject extends BeanBase {
Object object;
Map<String, Field> fieldMap = new HashMap();
/**
* 获取映射关系
* @return
*/
public Map<String, Field> getFieldMap() {
return fieldMap;
}
/**
* 构造函数,生成所有的映射(成员与名字)
* @param obj
*/
public BeanObject(Object obj) {
this.object = obj;
Field[] fields = obj.getClass().getFields();
for (Field f : fields) {
String name = getFieldName(f);
fieldMap.put(name, f);
}
}
/**
* 获取字段名
* @param f
* @return
*/
public static String getFieldName(Field f) {
// SessionAttribute a = f.getAnnotation(SessionAttribute.class);
// if (a != null && a.Name() != null && a.Name().length() > 0) {
// return a.Name();
// }
//
// Parameter p = f.getAnnotation(Parameter.class);
// if (p != null && p.Name() != null && p.Name().length() > 0) {
// return p.Name();
// }
return f.getName();
}
/**
* 获取字段名对应的值
*/
@Override
public Object get(String name) {
if(name == null)return null;
String[] names = name.split("\\.", 2);
if(names.length==2){
Object object = get(names[0]);
if(object == null){
return null;
}
return BeanFactory.newBean(object).get(names[1]);
}
Field field = fieldMap.get(name);
if (field == null)
return null;
try {
return field.get(object);
} catch (IllegalArgumentException e) {
System.err.println("exception: object " + object + " field " + name
+ " illegal argument");
} catch (IllegalAccessException e) {
System.err.println("exception object " + object + " field " + name
+ " not public");
}
return null;
}
/**
* 是否包含字段名?
*/
@Override
public boolean contains(String key) {
return fieldMap.containsKey(key);
}
/**
* 设置字段的值
*/
@Override
public void set(String name, Object value) {
if (value == null)
return;
String[] names = name.split("\\.", 2);
if(names.length==2){
Object object = get(names[0]);
if(object == null){
return;
}
BeanFactory.newBean(object).set(names[1], value);
return;
}
try {
Field field = fieldMap.get(name);
if(field==null){
return;
}
if (field.getType() != value.getClass()) {
if (value.getClass() != String.class) {
value = value.toString();
}
if (field.getType().isArray()) {
Class cls = field.getType().getComponentType();
if (cls == Integer.class) {
String[] ss = value.toString().split(",");
Integer[] t = new Integer[ss.length];
for(int i=0;i<ss.length;i++){
t[i] = Integer.valueOf(ss[i], 10);
}
field.set(object, t);
return;
}
if (cls == Float.class) {
String[] ss = value.toString().split(",");
Float[] t = new Float[ss.length];
for(int i=0;i<ss.length;i++){
t[i] = Float.valueOf(ss[i]);
}
field.set(object, t);
return;
}
if (cls == String.class) {
String[] ss = value.toString().split(",");
field.set(object, ss);
return;
}
}
value = CasterFactory
.valueOf(field.getType(), (String) value);
}
field.set(object, value);
} catch (Exception e) {
System.out.println("exception: "+name);
e.printStackTrace();
}
}
@Override
public Set keySet() {
return fieldMap.keySet();
}
@Override
public Object get() {
return object;
}
}
可以看出,这个类的作用就是将一个key-value的Map映射到对应的java类属性中,这也是业务层前端实现的。(如果想更加详细的了解,请阅读源码)
此外db
模块对于那些没有对应java类的查询也做了一层封装处理(转为为Map的链表),例如下面我只想获取弹幕的昵称还有内容,不需要将所有字段返回,可以这么写:
package alien.art;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.connector.Request;
import org.apache.catalina.tribes.group.interceptors.TwoPhaseCommitInterceptor.MapEntry;
import com.angroid.autogenerate.handler.vericode;
import com.angroid.db.SQLExecutor;
import com.angroid.dojo.Danmaku;
import com.angroid.dojo.Room;
public class test{
public static void main(String[] args) {
List<Map> res = SQLExecutor.find("select nickname, content from danmaku where id = 13");
for(Map map : res) {
if(map.containsKey("nickname"))
System.out.println("nickname: " + map.get("nickname"));
if(map.containsKey("content"))
System.out.println("content: " + map.get("content"));
}
}
}
/*返回结果
select nickname, content from danmaku where id = 13
[]
word: select
word: nickname
word: content
word: from
word: danmaku
word: where
nickname: 仙女爸爸0818
content: 我的小妲己不敢玩了
*/
至此,数据库模块再也没有什么秘密了,只要再仔细阅读源码能更加明白作者的意图。
网友评论