2021SC@SDUSC
继续上周的分析
在方法SQLConfig newSQLConfig(RequestMethod method, String table, String alias, JSONObject request, List<Join> joinList, boolean isProcedure, Callback callback) throws Exception {}中,定义了如下变量
String role = request.getString(KEY_ROLE);
String cache = request.getString(KEY_CACHE);
String combine = request.getString(KEY_COMBINE);
Subquery from = (Subquery) request.get(KEY_FROM);
String column = request.getString(KEY_COLUMN);
String group = request.getString(KEY_GROUP);
String having = request.getString(KEY_HAVING);
String order = request.getString(KEY_ORDER);
String raw = request.getString(KEY_RAW);
String json = request.getString(KEY_JSON);
对JSONObject request 的getString方法,获得相应的变量
关于变量的解释,在JSONObject类中有详细注释如下
public static final String KEY_TRY = "@try"; //尝试,忽略异常
public static final String KEY_CATCH = "@catch"; //TODO 捕捉到异常后,处理方式 null-不处理;DEFAULT-返回默认值;ORIGIN-返回请求里的原始值
public static final String KEY_DROP = "@drop"; //丢弃,不返回,TODO 应该通过 fastjson 的 ignore 之类的机制来处理,避免导致下面的对象也不返回
// public static final String KEY_KEEP = "@keep"; //一定会返回,为 null 或 空对象时,会使用默认值(非空),解决其它对象因为不关联的第一个对为空导致也不返回
public static final String KEY_DEFULT = "@default"; //TODO 自定义默认值 { "@default":true },@default 可完全替代 @keep
public static final String KEY_NULL = "@null"; //TODO 值为 null 的键值对 "@null":"tag,pictureList",允许 is NULL 条件判断, SET tag = NULL 修改值为 NULL 等
public static final String KEY_ROLE = "@role"; //角色,拥有对某些数据的某些操作的权限
public static final String KEY_DATABASE = "@database"; //数据库类型,默认为MySQL
public static final String KEY_SCHEMA = "@schema"; //数据库,Table在非默认schema内时需要声明
public static final String KEY_DATASOURCE = "@datasource"; //数据源
public static final String KEY_EXPLAIN = "@explain"; //分析 true/false
public static final String KEY_CACHE = "@cache"; //缓存 RAM/ROM/ALL
public static final String KEY_COLUMN = "@column"; //查询的Table字段或SQL函数
在对APIJSON的分析中,我的同学分析了JSONObject类
地址如下
(31条消息) 代码分析八_鲲不鲲的博客-优快云博客
同学的代码详细的分析了JSONObject类的定义和用途
下面是在一个try{}内
//强制作为条件且放在最前面优化性能
request.remove(idKey);
request.remove(idInKey);
//关键词
request.remove(KEY_ROLE);
request.remove(KEY_EXPLAIN);
request.remove(KEY_CACHE);
request.remove(KEY_DATASOURCE);
request.remove(KEY_DATABASE);
request.remove(KEY_SCHEMA);
request.remove(KEY_COMBINE);
request.remove(KEY_FROM);
request.remove(KEY_COLUMN);
request.remove(KEY_GROUP);
request.remove(KEY_HAVING);
request.remove(KEY_ORDER);
request.remove(KEY_RAW);
request.remove(KEY_JSON);
这里remove是移除了request的内部变量
String[] rawArr = StringUtil.split(raw);
config.setRaw(rawArr == null || rawArr.length <= 0 ? null : new ArrayList<>(Arrays.asList(rawArr)));
Map<String, Object> tableWhere = new LinkedHashMap<String, Object>();//保证顺序好优化 WHERE id > 1 AND name LIKE...
这里用到了StringUtils.split(),作用是分割字符
config.setRaw(rawArr == null || rawArr.length <= 0 ? null : new ArrayList<(Arrays.asList(rawArr)));
这里设置了config的raw,rawArr == null || rawArr.length <= 0时,设为null
不为空时设为new ArrayList<(Arrays.asList(rawArr))
Map<String, Object> tableWhere = new LinkedHashMap<String, Object>();
//保证顺序好优化 WHERE id > 1 AND name LIKE...
这里用到了Map<String, Object>
Map是一个接口,即Interface Map<K,V>,其中K-key类型和V-value的类型
它的每个元素包含一个key对象和一个value对象,且在这两个对象之间存在一种映射的对应关系,所有从Map集合中访问元素时,只有指定了key就可以找到对应的value,因此key必须是唯一的且不能重复,当key相同时,后面的value值会覆盖之前的value值。
Map定义的一些通用的方法
Map接口有很多实现类,如TreeMap,Hashtable,SortedMap,HashMap。
LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。LinkedHashMap实现与HashMap的不同之处在于,LinkedHashMap维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序(insert-order)或者是访问顺序,其中默认的迭代访问顺序就是插入顺序,即可以按插入的顺序遍历元素,这点和HashMap有很大的不同。
知识学习
org.apache.commons.lang.StringUtils中方法的操作对象是java.lang.String类型的对象,是JDK提供的String类型操作方法的补充,并且是null安全的(即如果输入参数String为null则不会抛出NullPointerException,而是做了相应处理,例如,如果输入为null则返回也是null等,具体可以查看源代码)。
除了构造器,StringUtils中一共有130多个方法,并且都是static的,
所以我们可以这样调用StringUtils.xxx()。
53.public static String[] split(String str, char separatorChar)
把字符串拆分成一个字符串数组,用指定的字符separatorChar作为分隔符。
如果字符串为null,返回null
如果字符串为"",返回空数组{}
举例(*表示任意):
StringUtils.split(null, *) = null
StringUtils.split("", *) = {}
StringUtils.split("as df yy",' ')) = {"as","df","yy"}
StringUtils.split(" as df yy ",' ')) = {"as","df","yy"}
StringUtils.split("asodfoyy",'o')) = {"as","df","yy"}
StringUtils.split("as.df.yy",'.')) = {"as","df","yy"}
StringUtils.split("as\ndf\nyy",'\n'))= {"as","df","yy"}
StringUtils.split("as",' ')) = {"as"}
StringUtils.split(" as ",' ')) = {"as"}
更多使用方法可以查看下面这篇文章
下面是POST操作和非POST操作
if (method == POST) { //POST操作
if (idIn != null) {
throw new IllegalArgumentException("POST 请求中不允许传 " + idInKey + " !");
}
if (set != null && set.isEmpty() == false) { //不能直接return,要走完下面的流程
String[] columns = set.toArray(new String[]{});
Collection<Object> valueCollection = request.values();
Object[] values = valueCollection == null ? null : valueCollection.toArray();
if (values == null || values.length != columns.length) {
throw new Exception("服务器内部错误:\n" + TAG
+ " newSQLConfig values == null || values.length != columns.length !");
}
column = (id == null ? "" : idKey + ",") + StringUtil.getString(columns); //set已经判断过不为空
List<List<Object>> valuess = new ArrayList<>(1);
List<Object> items; //(item0, item1, ...)
if (id == null) { //数据库自增 id
items = Arrays.asList(values); //FIXME 是否还需要进行 add 或 remove 操作?Arrays.ArrayList 不允许修改,会抛异常
}
else {
int size = columns.length + (id == null ? 0 : 1); //以key数量为准
items = new ArrayList<>(size);
items.add(id); //idList.get(i)); //第0个就是id
for (int j = 1; j < size; j++) {
items.add(values[j-1]); //从第1个开始,允许"null"
}
}
valuess.add(items);
config.setValues(valuess);
}
}
else { //非POST操作
final boolean isWhere = method != PUT;//除了POST,PUT,其它全是条件!!!
//条件<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
List<String> whereList = null;
Map<String, List<String>> combineMap = new LinkedHashMap<>();
List<String> andList = new ArrayList<>();
List<String> orList = new ArrayList<>();
List<String> notList = new ArrayList<>();
//强制作为条件且放在最前面优化性能
if (id != null) {
tableWhere.put(idKey, id);
andList.add(idKey);
}
if (idIn != null) {
tableWhere.put(idInKey, idIn);
andList.add(idInKey);
}
String[] ws = StringUtil.split(combine);
if (ws != null) {
if (method == DELETE || method == GETS || method == HEADS) {
throw new IllegalArgumentException("DELETE,GETS,HEADS 请求不允许传 @combine:value !");
}
whereList = new ArrayList<>();
String w;
for (int i = 0; i < ws.length; i++) { //去除 &,|,! 前缀
w = ws[i];
if (w != null) {
if (w.startsWith("&")) {
w = w.substring(1);
andList.add(w);
}
else if (w.startsWith("|")) {
if (method == PUT) {
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!"
+ "PUT请求的 @combine:\"key0,key1,...\" 不允许传 |key 或 !key !");
}
w = w.substring(1);
orList.add(w);
}
else if (w.startsWith("!")) {
if (method == PUT) {
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!"
+ "PUT请求的 @combine:\"key0,key1,...\" 不允许传 |key 或 !key !");
}
w = w.substring(1);
notList.add(w);
}
else {
orList.add(w);
}
if (w.isEmpty()) {
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!不允许为空值!");
}
else {
if (idKey.equals(w) || idInKey.equals(w) || userIdKey.equals(w) || userIdInKey.equals(w)) {
throw new UnsupportedOperationException(table + ":{} 里的 @combine:value 中的value里 " + ws[i] + " 不合法!"
+ "不允许传 [" + idKey + ", " + idInKey + ", " + userIdKey + ", " + userIdInKey + "] 其中任何一个!");
}
}
whereList.add(w);
}
// 可重写回调方法自定义处理 // 动态设置的场景似乎很少,而且去掉后不方便用户排错!//去掉判断,有时候不在没关系,如果是对增删改等非开放请求强制要求传对应的条件,可以用 Operation.NECESSARY
if (request.containsKey(w) == false) { //和 request.get(w) == null 没区别,前面 Parser 已经过滤了 null
// throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里 " + ws[i] + " 对应的 " + w + " 不在它里面!");
callback.onMissingKey4Combine(table, request, combine, ws[i], w);
}
}
}
//条件>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Map<String, Object> tableContent = new LinkedHashMap<String, Object>();
Object value;
for (String key : set) {
value = request.get(key);
if (value instanceof Map) {//只允许常规Object
throw new IllegalArgumentException("不允许 " + key + " 等任何key的value类型为 {JSONObject} !");
}
//解决AccessVerifier新增userId没有作为条件,而是作为内容,导致PUT,DELETE出错
if (isWhere || (StringUtil.isName(key) == false)) {
tableWhere.put(key, value);
if (whereList == null || whereList.contains(key) == false) {
andList.add(key);
}
}
else if (whereList != null && whereList.contains(key)) {
tableWhere.put(key, value);
}
else {
tableContent.put(key, value);//一样 instanceof JSONArray ? JSON.toJSONString(value) : value);
}
}
combineMap.put("&", andList);
combineMap.put("|", orList);
combineMap.put("!", notList);
config.setCombine(combineMap);
config.setContent(tableContent);
}
POST操作时,
set != null && set.isEmpty() == false,set不为空的情况下
定义了以下变量
Collection<Object> valueCollection,Object[] values,
List<List<Object>> valuess,List<Object> items;
然后对变量进行处理
valuess.add(items);
config.setValues(valuess);
对于非POST操作
final boolean isWhere = method != PUT;//除了POST,PUT,其它全是条件!!!
List<String> whereList = null;
Map<String, List<String>> combineMap = new LinkedHashMap<>();
List<String> andList = new ArrayList<>();
List<String> orList = new ArrayList<>();
List<String> notList = new ArrayList<>();
定义了以上条件列表
然后String[] ws = StringUtil.split(combine);进行拆分操作
if (method == DELETE || method == GETS || method == HEADS) {
throw new IllegalArgumentException("DELETE,GETS,HEADS 请求不允许传 @combine:value !");
}
要注意的是DELETE,GETS,HEADS 请求不允许传 @combine:value
对拆分后得到的ws进行字符处理,根据不同的字符加入到不同的list
最后添加数据到定义的List
combineMap.put("&", andList);
combineMap.put("|", orList);
combineMap.put("!", notList);
config.setCombine(combineMap);
config.setContent(tableContent);
List<String> cs = new ArrayList<>();
List<String> rawList = config.getRaw();
boolean containColumnRaw = rawList != null && rawList.contains(KEY_COLUMN);
String rawColumnSQL = null;
if (containColumnRaw) {
try {
rawColumnSQL = config.getRawSQL(KEY_COLUMN, column);
if (rawColumnSQL != null) {
cs.add(rawColumnSQL);
}
} catch (Exception e) {
Log.e(TAG, "newSQLConfig config instanceof AbstractSQLConfig >> try { "
+ " rawColumnSQL = ((AbstractSQLConfig) config).getRawSQL(KEY_COLUMN, column); "
+ "} catch (Exception e) = " + e.getMessage());
}
}
这里定义了List<String> cs,List<String> rawList
判断条件boolean containColumnRaw = rawList != null && rawList.contains(KEY_COLUMN);
rawColumnSQL = config.getRawSQL(KEY_COLUMN, column);
if (rawColumnSQL != null) {
cs.add(rawColumnSQL);
}
cs添加了 config.getRawSQL(KEY_COLUMN, column)不为空的内容
boolean distinct = column == null || rawColumnSQL != null ? false : column.startsWith(PREFFIX_DISTINCT);
if (rawColumnSQL == null) {
String[] fks = StringUtil.split(distinct ? column.substring(PREFFIX_DISTINCT.length()) : column, ";"); // key0,key1;fun0(key0,...);fun1(key0,...);key3;fun2(key0,...)
if (fks != null) {
String[] ks;
for (String fk : fks) {
if (containColumnRaw) {
try {
String rawSQL = config.getRawSQL(KEY_COLUMN, fk);
if (rawSQL != null) {
cs.add(rawSQL);
continue;
}
} catch (Exception e) {
Log.e(TAG, "newSQLConfig rawColumnSQL == null >> try { "
+ " String rawSQL = ((AbstractSQLConfig) config).getRawSQL(KEY_COLUMN, fk); ... "
+ "} catch (Exception e) = " + e.getMessage());
}
}
if (fk.contains("(")) { // fun0(key0,...)
cs.add(fk);
}
else { //key0,key1...
ks = StringUtil.split(fk);
if (ks != null && ks.length > 0) {
cs.addAll(Arrays.asList(ks));
}
}
}
}
}
定义的判断条件是boolean distinct = column == null || rawColumnSQL != null ? false : column.startsWith(PREFFIX_DISTINCT);
rawColumnSQL == null时,
String[] fks = StringUtil.split(distinct ? column.substring(PREFFIX_DISTINCT.length()) : column, ";");
// key0,key1;fun0(key0,...);fun1(key0,...);key3;fun2(key0,...)
将column.substring(PREFFIX_DISTINCT.length()) 或column拆分
fks 不为空时,用for (String fk : fks)对fks循环处理
String rawSQL = config.getRawSQL(KEY_COLUMN, fk);
加入到cs: cs.add(rawSQL);
设置了异常
Log.e(TAG, "newSQLConfig rawColumnSQL == null >> try { "
+ " String rawSQL = ((AbstractSQLConfig) config).getRawSQL(KEY_COLUMN, fk); ... "
+ "} catch (Exception e) = " + e.getMessage());
config.setExplain(explain);
config.setCache(getCache(cache));
config.setFrom(from);
config.setDistinct(distinct);
config.setColumn(column == null ? null : cs); //解决总是 config.column != null,总是不能得到 *
config.setWhere(tableWhere);
config.setId(id);
//在 tableWhere 第0个 config.setIdIn(idIn);
config.setRole(RequestRole.get(role));
config.setGroup(group);
config.setHaving(having);
config.setOrder(order);
String[] jsonArr = StringUtil.split(json);
config.setJson(jsonArr == null || jsonArr.length <= 0 ? null : new ArrayList<>(Arrays.asList(jsonArr)));
//TODO 解析JOIN,包括 @column,@group 等要合并
然后设置config的配置
最后还有一个Finally,还原了配置,对应前文的remove
finally {//后面还可能用到,要还原
//id或id{}条件
if (hasId) {
request.put(idKey, id);
}
request.put(idInKey, idIn);
//关键词
request.put(KEY_DATABASE, database);
request.put(KEY_ROLE, role);
request.put(KEY_EXPLAIN, explain);
request.put(KEY_CACHE, cache);
request.put(KEY_DATASOURCE, datasource);
request.put(KEY_SCHEMA, schema);
request.put(KEY_COMBINE, combine);
request.put(KEY_FROM, from);
request.put(KEY_COLUMN, column);
request.put(KEY_GROUP, group);
request.put(KEY_HAVING, having);
request.put(KEY_ORDER, order);
request.put(KEY_RAW, raw);
request.put(KEY_JSON, json);
}
自此return config;
方法SQLConfig newSQLConfig(RequestMethod method, String table, String alias, JSONObject request, List<Join> joinList, boolean isProcedure, Callback callback) throws Exception {}结束
3268
本文详细解析了APIJSON框架中AbstractSQLConfig类的newSQLConfig方法,涉及到JSONObject处理、Map数据结构使用、StringUtils工具类的split方法以及各种条件处理。通过分析请求方法、数据表、别名、请求参数等,构建SQL配置对象,包括设置原始值、处理WHERE条件、COMBINE组合条件等关键步骤。

752

被折叠的 条评论
为什么被折叠?



