APIJSON 博客4 AbstractSQLConfig 第四篇

2021SC@SDUSC

继续上周对AbstractSQLConfig的分析,后面的代码是@override

@Override
	public boolean isExplain() {
		return explain;
	}
	@Override
	public AbstractSQLConfig setExplain(boolean explain) {
		this.explain = explain;
		return this;
	}

	@Override
	public List<Join> getJoinList() {
		return joinList;
	}

知识学习

@Override是伪代码,表示重写。(当然不写@Override也可以),不过写上有如下好处: 
1、可以当注释用,方便阅读;
2、编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错。例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。
 
举例:在重写父类的onCreate时,在方法前面加上@Override 系统可以帮你检查方法的正确性。
@Override
public void onCreate(Bundle savedInstanceState)

{…….}
这种写法是正确的,如果你写成:

@Override
public void oncreate(Bundle savedInstanceState)
{…….}
编译器会报如下错误:The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method,以确保你正确重写onCreate方法(因为oncreate应该为onCreate)。

而如果你不加@Override,则编译器将不会检测出错误,而是会认为你为子类定义了一个新方法:oncreate

 这里用到了@JSONField

@JSONField(serialize = false)
	public int getOffset() {
		return getOffset(getPage(), getCount());
	}
	/**获取初始位置offset
	 * @param page
	 * @param count
	 * @return
	 */
	public static int getOffset(int page, int count) {
		return page*count;
	}
	/**获取限制数量
	 * @return
	 */
	@JSONField(serialize = false)
	public String getLimitString() {
		if (count <= 0 || RequestMethod.isHeadMethod(getMethod(), true)) {
			return "";
		}
		return getLimitString(getPage(), getCount(), isOracle() || isSQLServer() || isDb2(), isOracle());
	}
    public static String getLimitString(int page, int count, boolean isTSQL, boolean isOracle) {
		int offset = getOffset(page, count);

		if (isTSQL) {  // OFFSET FECTH 中所有关键词都不可省略, 另外 Oracle 数据库使用子查询加 where 分页
			return isOracle ? " WHERE ROWNUM BETWEEN "+ offset +" AND "+ (offset + count) : " OFFSET " + offset + " ROWS FETCH FIRST " + count + " ROWS ONLY";
		}

		return " LIMIT " + count + (offset <= 0 ? "" : " OFFSET " + offset);  // DELETE, UPDATE 不支持 OFFSET
	}

知识学习

FastJson中@JSONField注解使用
json格式在服务器之间进行数据传输。但是json格式数据不符合JAVA中的变量定义规则,并且难以理解,因此需要在后台中做二次处理,将数据处理成我们系统中定义的格式。

思路:

    1. 定义需要返回的bean,bean中定义需要返回的数据

    2. 获取到需要处理的JSON字符串

    3. 将JSON字符串转换为bean, 再将转换后的bean返回给客户端。

由于json中的key与bean中的属性不能匹配,因此在转换过程中出现了部分属性为null的情况。经过查看官方文档,发现可以使用@JSONField进行解释,但是并没有详细的使用说明。

@JSONField的作用对象:

1. Field
2. Setter 和 Getter方法

注:FastJson在进行操作时,是根据getter和setter的方法进行的,并不是依据Field进行。

Show me the code:

一、作用Field

@JSONField作用在Field时,其name不仅定义了输入key的名称,同时也定义了输出的名称。当@JSONField作用在Fileld上时,定义了输入和输出,如果我们传输过来的json格式不符合这个格式时,则不能够正确转换。

二、作用在setter和getter方法上

顾名思义,当作用在setter方法上时,就相当于根据 name 到 json中寻找对应的值,并调用该setter对象赋值。

当作用在getter上时,在bean转换为json时,其key值为name定义的值。

下面是对getwhereString的解析

Set<Entry<String, List<String>>> combineSet = combine == null ? null : combine.entrySet();

这里使用set方法定义了combineSet

知识学习

Set是集合的意思,是同种对象的集合,<String>说明这种对象都是String类型的对象。

可以这样:

Set<String> set = new HashSet<String>();
String s1 = "hello";

String s2 = "world";

set.add(s1);

set.add(s2);
这样就添加了两个元素。

		for (Entry<String, List<String>> ce : combineSet) {
			keyList = ce == null ? null : ce.getValue();
			if (keyList == null || keyList.isEmpty()) {
				continue;
			}

			if ("|".equals(ce.getKey())) {
				logic = Logic.TYPE_OR;
			}
			else if ("!".equals(ce.getKey())) {
				logic = Logic.TYPE_NOT;
			}
			else {
				logic = Logic.TYPE_AND;
			}


			isItemFirst = true;
			cs = "";
			for (String key : keyList) {
				c = getWhereItem(key, where.get(key), method, verifyName);

				if (StringUtil.isEmpty(c, true)) {//避免SQL条件连接错误
					continue;
				}

				cs += (isItemFirst ? "" : (Logic.isAnd(logic) ? AND : OR)) + "(" + c + ")";

				isItemFirst = false;
			}

			if (StringUtil.isEmpty(cs, true)) {//避免SQL条件连接错误
				continue;
			}

			whereString += (isCombineFirst ? "" : AND) + (Logic.isNot(logic) ? NOT : "") + " (  " + cs + "  ) ";
			isCombineFirst = false;
		}

 这里是对SQL语言中WHERE语句的SQL连接,条件的判断,后面还有对join的错误类型判断,大概分以下几种

throw new NotExistException("no result for ! OUTER JOIN( ! (A | B) ) when A or B is empty!")

throw new NotExistException("no result for ) FOREIGN JOIN( B & ! A ) when A is empty!");

throw new NotExistException("no result for ! OUTER JOIN( ! (A | B) ) when A or B is empty!");

throw new NotExistException("no result for ( ANTI JOIN( A & ! B ) when B is empty!");

throw new NotExistException("no result for ^ SIDE JOIN( ! (A & B) ) when both A and B are empty!");

throw new UnsupportedOperationException("写操作请求必须带条件!!!");

protected String getWhereItem(String key, Object value, RequestMethod method, boolean verifyName) throws Exception {
		Log.d(TAG, "getWhereItem  key = " + key);
		//避免筛选到全部	value = key == null ? null : where.get(key);
		if (key == null || value == null || key.endsWith("()") || key.startsWith("@")) { //关键字||方法, +或-直接报错
			Log.d(TAG, "getWhereItem  key == null || value == null"
					+ " || key.startsWith(@) || key.endsWith(()) >> continue;");
			return null;
		}
		if (key.endsWith("@")) {//引用
			//	key = key.substring(0, key.lastIndexOf("@"));
			throw new IllegalArgumentException(TAG + ".getWhereItem: 字符 " + key + " 不合法!");
		}

		// 原始 SQL 片段
		String rawSQL = getRawSQL(key, value);

		int keyType;
		if (key.endsWith("$")) {
			keyType = 1;
		} 
		else if (key.endsWith("~")) {
			keyType = key.charAt(key.length() - 2) == '*' ? -2 : 2;  //FIXME StringIndexOutOfBoundsException
		}
		else if (key.endsWith("%")) {
			keyType = 3;
		}
		else if (key.endsWith("{}")) {
			keyType = 4;
		}
		else if (key.endsWith("}{")) {
			keyType = 5;
		}
		else if (key.endsWith("<>")) {
			keyType = 6;
		}
		else if (key.endsWith(">=")) {
			keyType = 7;
		}
		else if (key.endsWith("<=")) {
			keyType = 8;
		}
		else if (key.endsWith(">")) {
			keyType = 9;
		}
		else if (key.endsWith("<")) {
			keyType = 10;
		} else {  // else绝对不能省,避免再次踩坑! keyType = 0; 写在for循环外面都没注意!
			keyType = 0;
		}

		key = getRealKey(method, key, false, true, verifyName);

		switch (keyType) {
		case 1:
			return getSearchString(key, value, rawSQL);
		case -2:
		case 2:
			return getRegExpString(key, value, keyType < 0, rawSQL);
		case 3:
			return getBetweenString(key, value, rawSQL);
		case 4:
			return getRangeString(key, value, rawSQL);
		case 5:
			return getExistsString(key, value, rawSQL);
		case 6:
			return getContainString(key, value, rawSQL);
		case 7:
			return getCompareString(key, value, ">=", rawSQL);
		case 8:
			return getCompareString(key, value, "<=", rawSQL);
		case 9:
			return getCompareString(key, value, ">", rawSQL);
		case 10:
			return getCompareString(key, value, "<", rawSQL);
		default:  // TODO MySQL JSON类型的字段对比 key='[]' 会无结果! key LIKE '[1, 2, 3]'  //TODO MySQL , 后面有空格!
			return getEqualString(key, value, rawSQL);
		}
	}

这里对不同的符号进行了不同的处理 

用到了后面定义的方法getRegExpString, getBetweenString,getRangeString,getExistsString, getContainString,getEqualString下一篇博客会来分析一下这些方法

下面是getRegExpString

	@JSONField(serialize = false)
	public String getRegExpString(String key, Object value, boolean ignoreCase, String rawSQL) throws IllegalArgumentException {
		if (rawSQL != null) {
			throw new UnsupportedOperationException("@raw:value 中 " + key + " 不合法!@raw 不支持 key~ 这种功能符 !只支持 key, key!, key<, key{} 等比较运算 和 @column, @having !");
		}
		if (value == null) {
			return "";
		}

		Logic logic = new Logic(key);
		key = logic.getKey();
		Log.i(TAG, "getRegExpString key = " + key);

		JSONArray arr = newJSONArray(value);
		if (arr.isEmpty()) {
			return "";
		}
		return getRegExpString(key, arr.toArray(), logic.getType(), ignoreCase);
	}
	/**search key match RegExp values
	 * @param key
	 * @param values
	 * @param type 
	 * @param ignoreCase 
	 * @return LOGIC [  key REGEXP 'values[i]' ]
	 * @throws IllegalArgumentException 
	 */
	@JSONField(serialize = false)
	public String getRegExpString(String key, Object[] values, int type, boolean ignoreCase) throws IllegalArgumentException {
		if (values == null || values.length <= 0) {
			return "";
		}

		String condition = "";
		for (int i = 0; i < values.length; i++) {
			if (values[i] instanceof String == false) {
				throw new IllegalArgumentException(key + "$:value 中value的类型只能为String或String[]!");
			}
			condition += (i <= 0 ? "" : (Logic.isAnd(type) ? AND : OR)) + getRegExpString(key, (String) values[i], ignoreCase);
		}

		return getCondition(Logic.isNot(type), condition);
	}

	/**WHERE key REGEXP 'value'
	 * @param key
	 * @param value
	 * @param ignoreCase
	 * @return key REGEXP 'value'
	 */
	@JSONField(serialize = false)
	public String getRegExpString(String key, String value, boolean ignoreCase) {
		if (isPostgreSQL()) {
			return getKey(key) + " ~" + (ignoreCase ? "* " : " ") + getValue(value);
		}
		if (isOracle()) {
			return "regexp_like(" + getKey(key) + ", " + getValue(value) + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
		}
		if (isClickHouse()) {
			return "match(" + (ignoreCase ? "lower(" : "") + getKey(key) + (ignoreCase ? ")" : "") + ", " + (ignoreCase ? "lower(" : "") + getValue(value) + (ignoreCase ? ")" : "") + ")";
		}
		return getKey(key) + " REGEXP " + (ignoreCase ? "" : "BINARY ") + getValue(value);
	}

这里也用到了Log中的方法

public static boolean DEBUG = true;

    public static void d(String TAG, String msg) {
        if (DEBUG) {
            logInfo(TAG,msg,"DEBUG");
        }
    }

这里又用到了loginfo方法如下

    public static void logInfo(String TAG, String msg, String level){
        if(level.equals("DEBUG") || level .equals("ERROR") ||level.equals("WARN")){
            System.err.println(dateFormat.format(System.currentTimeMillis()) + ": " + TAG + "." + level + ": " + msg);
        }
        else if(level.equals("VERBOSE") || level .equals("INFO") ){
            System.out.println(dateFormat.format(System.currentTimeMillis()) + ": " + TAG + "." + level + ": " + msg);
        }
    }

这是对调用方法的日志信息表记录,出错时和未出错时的记录

知识学习

System.err和System.out的区别?
①java API,文档中给出的解释是:out为“标准输出流”,err为“标准错误输出流”;  

②在eclipse里运行时差别就是,二者显示的颜色有所区别,err输出显示为红色 ;      

③err.println输出的字符串位置会随机出现。但,err.println输出的字符串之间的相对位置不会改变,System.out在JVM和操作系统都具有缓存功能,就是你输出的东西不一定实时输出,有时候会积攒到一定数量才会输出,System.err会实时输出,单独使用的话可能感觉不到,如果两种方式混合使用就会发现了 。

记录位置1957 

上一篇:Python判断字符串是否为字母或者数字


下一篇:自定义俄罗斯方块