自定义ORM实现(mybatis)

106 阅读1分钟

简介

ORM框架是对象关系映射框架的简称,是一种可以让程序员使用面向对象的方式来操作数据库的工具,它将数据库中的表和行转换成对象和属性,使得程序员可以通过面向对象的方式来进行数据库操作,这样可以避免了直接使用SQL语言对数据库进行操作时的复杂性和繁琐性。

前端

使用代码编辑器CodeMirror实现跟mybatis一样的语法

后端

使用dom4j对xml字符串进行解析赋值

public class XmlUtils {

	public static String sqlAnalysis(String text, Map<String, Object> params, String id) {
		try {
			text = text.replaceAll("<!--.*?-->", "");
			text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + text;
			Document document = DocumentHelper.parseText(text);
			Element rootElement = document.getRootElement();
			return resolveNode(rootElement, params, id);
		} catch (DocumentException e) {
			throw new GrammarException("xml语法错误");
		}
	}

	@SuppressWarnings("unchecked")
	public static String resolveNode(Element target, Map<String, Object> params, String id) {
		StringBuilder sql = new StringBuilder();
		List<Node> list = target.content();
		for (int i = 0; i < list.size(); i++) {
			Node node = list.get(i);
			String typeName = node.getNodeTypeName();
			if (typeName.equals("Text")) {
				String text = replace(node.getText(), params);
				sql.append(text);
			} else if (typeName.equals("Element")) {
				Element element = (Element) node;
				String eleName = element.getName();
				if (eleName.equals("select") || eleName.equals("insert") || eleName.equals("update")
						|| eleName.equals("delete")) {
					Attribute attribute = element.attribute("id");
					if (attribute != null) {
						if (attribute.getValue().equals(id)) {
							sql.append(resolveNode(element, params, id));
							break;
						}
					} else {
						sql.append(resolveNode(element, params, id));
					}
				} else if (eleName.equals("where")) {
					String text = resolveNode(element, params, id).trim();
					if(!StringUtils.isEmpty(text)) {
						text = " WHERE " + text;
						if(text.startsWith(" WHERE AND ")) {
							text = text.replaceAll(" WHERE AND ", " WHERE ");
						}
						if(text.startsWith(" WHERE and ")) {
							text = text.replaceAll(" WHERE and ", " WHERE ");
						}
						if(text.startsWith(" WHERE OR ")) {
							text = text.replaceAll(" WHERE OR ", " WHERE ");
						}
						if(text.startsWith(" WHERE or ")) {
							text = text.replaceAll(" WHERE or ", " WHERE ");
						}
						sql.append(text);
					}
				} else if (eleName.equals("if")) {
					Attribute attribute = element.attribute("test");
					if (attribute != null) {
						String attrValue = attribute.getValue();
						attrValue = attrValue.replaceAll(" and ", " && ");
						attrValue = attrValue.replaceAll(" or ", " || ");
						try {
							JexlEngine jexl = new JexlBuilder().create();
							JexlContext context = new MapContext(params);
							JexlExpression expression = jexl.createExpression(attrValue);
							if ((boolean) expression.evaluate(context)) {
								sql.append(resolveNode(element, params, id));
							}
						} catch (Exception e) {
							// e.printStackTrace();
						}
					} else {
						throw new GrammarException("if语法缺少test属性");
					}
				} else if (eleName.equals("foreach")) {
					Attribute collectionAttribute = element.attribute("collection");
					if (collectionAttribute == null) {
						throw new GrammarException("foreach语法缺少collection属性");
					}
					Attribute itemAttribute = element.attribute("item");
					if (itemAttribute == null) {
						throw new GrammarException("foreach语法缺少item属性");
					}
					Attribute indexAttribute = element.attribute("index");
					Attribute separatorAttribute = element.attribute("separator");
					Attribute openAttribute = element.attribute("open");
					Attribute closeAttribute = element.attribute("close");

					String collection = collectionAttribute.getValue();
					if (params.get(collection) == null) {
		                // 语法错误
		                throw new GrammarException(collectionAttribute.getValue() + "参数不能为空");
		            }
					String item = itemAttribute.getValue();
					String separator = "";
					if (separatorAttribute != null) {
						separator = separatorAttribute.getValue();
					}
					String index = "";
					if (indexAttribute != null) {
						index = indexAttribute.getValue();
					}
					String open = "";
					if (openAttribute != null) {
						open = openAttribute.getValue();
					}
					String close = "";
					if (closeAttribute != null) {
						close = closeAttribute.getValue();
					}
					sql.append(open);
					if (params.get(collection).getClass().isArray()) {
						// array
						Object[] collectionArray = (Object[]) params.get(collection);
						for (int j = 0; j < collectionArray.length; j++) {
							params.put(item, collectionArray[j]);
							if (!StringUtils.isEmpty(index)) {
								params.put(index, j);
							}
							sql.append(resolveNode(element, params, id));
							if (j != (collectionArray.length - 1)) {
								sql.append(separator);
							}
						}
					} else if (params.get(collection) instanceof Collection) {
						// list
						List<Object> collectionList = (List<Object>) params.get(collection);
						for (int j = 0; j < collectionList.size(); j++) {
							params.put(item, collectionList.get(j));
							if (!StringUtils.isEmpty(index)) {
								params.put(index, j);
							}
							sql.append(resolveNode(element, params, id));
							if (j != (collectionList.size() - 1)) {
								sql.append(separator);
							}
						}
					} else if (params.get(collection) instanceof Map) {
						// map
						// Map<String, Object> collectionMap = (Map<String, Object>)
						// params.get(collection);

					}
					sql.append(close);
					params.remove(item);
					if (!StringUtils.isEmpty(index)) {
						params.remove(index);
					}
				} else if (eleName.equals("set")) {
					sql.append(" set ");
					sql.append(resolveNode(element, params, id));
				}
			}
		}
		String result = sql.toString();
		result = result.replaceAll("<", "<");
		result = result.replaceAll("<=", "<=");
		result = result.replaceAll(">", ">");
		result = result.replaceAll(">=", ">=");
		return result;
	}

	@SuppressWarnings("unchecked")
	public static String replace(String expression, Map<String, Object> env) {
		Pattern pattern = Pattern.compile("(\\#\\{[^}]+\\})");
		Matcher matcher = pattern.matcher(expression);
		while (matcher.find()) {
			String field = matcher.group(1).substring(2, matcher.group(1).length() - 1);
			if (env != null) {
				if(field.contains(".")) {
					String parentField = field.split("\\.")[0];
					String subField = field.split("\\.")[1];
					Map<String, Object> value = (Map<String, Object>) env.get(parentField);
					if (!StringUtils.isEmpty(value.get(subField))) {
						if (value.get(subField) instanceof String) {
							expression = expression.replaceAll("#\\{" + field + "\\}",
									"'" + StringEscapeUtils.escapeSql(value.get(subField).toString()) + "'");
						} else {
							expression = expression.replaceAll("#\\{" + field + "\\}", value.get(subField).toString());
						}
					} else {
						expression = expression.replaceAll("#\\{" + field + "\\}", "null");
					}
				} else {
					if (!StringUtils.isEmpty(env.get(field))) {
						if(field.contains(".")) {
							String parentField = field.split("\\.")[0];
							String subField = field.split("\\.")[1];
							Map<String, Object> value = (Map<String, Object>) env.get(parentField);
							if (value.get(subField) instanceof String) {
								expression = expression.replaceAll("#\\{" + field + "\\}",
										"'" + StringEscapeUtils.escapeSql(value.get(subField).toString()) + "'");
							} else {
								expression = expression.replaceAll("#\\{" + field + "\\}", value.get(subField).toString());
							}
						} else {
							if (env.get(field) instanceof String) {
								expression = expression.replaceAll("#\\{" + field + "\\}",
										"'" + StringEscapeUtils.escapeSql(env.get(field).toString()) + "'");
							} else {
								expression = expression.replaceAll("#\\{" + field + "\\}", env.get(field).toString());
							}
						}
					} else {
						expression = expression.replaceAll("#\\{" + field + "\\}", "null");
					}
				}
			} else {
				expression = expression.replaceAll("#\\{" + field + "\\}", "null");
			}
		}

		Pattern $pattern = Pattern.compile("(\\$\\{[^}]+\\})");
		Matcher $matcher = $pattern.matcher(expression);
		while ($matcher.find()) {
			String field = $matcher.group(1).substring(2, $matcher.group(1).length() - 1);
			if(field.contains(".")) {
				String parentField = field.split("\\.")[0];
				String subField = field.split("\\.")[1];
				Map<String, Object> value = (Map<String, Object>) env.get(parentField);
				if (!StringUtils.isEmpty(value.get(subField))) {
					expression = expression.replaceAll("\\$\\{" + field + "\\}",
							StringEscapeUtils.escapeSql(value.get(subField).toString()));
				} else {
					expression = expression.replaceAll("\\$\\{" + field + "\\}", "null");
				}
			} else {
				if (!StringUtils.isEmpty(env.get(field))) {
					expression = expression.replaceAll("\\$\\{" + field + "\\}",
							StringEscapeUtils.escapeSql(env.get(field).toString()));
				} else {
					expression = expression.replaceAll("\\$\\{" + field + "\\}", "null");
				}
			}
		}
		return expression;
	}
}