jpa自动封装sql

为了像django那样自动封装查询条件,我自己封装了一个生成hql的工具类.(__or条件会返回过来,需要自己再去处理)

contoller类:

@RestController
public class FengzhuangController {
	@Autowired
	private ArticleService articleService;
	@GetMapping("/auto-hql")
	public JsonResult<?> autoHql(@RequestParam Map<String,String> map, HttpSession session) {
		int page = 1;
		int limit = 20;
		if(map.containsKey("page")) page = Integer.parseInt(map.remove("page"));
		if(map.containsKey("limit")) limit = Integer.parseInt(map.remove("limit"));
		if(limit > 20) limit = 20;
		HqlHelper hh = null;
		try {
			hh = HqlHelper.buildHql("From Article", map);
		}catch(Exception e) {
			return JsonResult.errorResult(MsgEnum.SQL_ERROR);
		}
		if(hh.getOrMap().size()>0) {
			// or条件需要自己再封装Hql
		}
		List<Article> articles = articleService.findAllHql(hh.getHql() + " order by id desc",(page-1)*limit, limit);
		int total = articleService.getTotalHql(hh.getHql());
		Map<String,Object> rm = new HashMap<String, Object>();
		rm.put("articles", articles);
		rm.put("total", total);
		return JsonResult.successResult(rm);
	}
}

/**
* 约定只有后台能用,因为太强大了不安全
* 1. 比较: field__gt, field_lt, field_gte, field_lte, field__in, field__contains(两头加%即like), field__startwith(结尾加百分号), field__endwith(开头加百分号)
* 2.关联: __or:或关系, 无__or则是and关系
* 3.子对象: a.field__上面1__上面2(约定以a.开头)
*/

工具类:

/**
 *   后台hql生成类,因为只有后台才允许自由使用hql;
 */
public class HqlHelper {
	private String hql;
	private Map<String,String> orMap;
	public String getHql() {
		return hql;
	}
	public void setHql(String hql) {
		this.hql = hql;
	}

	public Map<String, String> getOrMap() {
		return orMap;
	}

	public void setOrMap(Map<String, String> orMap) {
		this.orMap = orMap;
	}

	/**
	 * 	约定只有后台能用,因为太强大了不安全
	 * 	1. 比较:  field__gt, field_lt, field_gte, field_lte, field__in, field__contains(两头加%即like), field__startwith(结尾加百分号), field__endwith(开头加百分号)
	 * 	2.关联:  __or:或关系, 无__or则是and关系
	 *  3.子对象: a.field__上面1__上面2(约定以a.开头)
	 */
	public static HqlHelper buildHql(String fromObject, Map<String,String> mapKv, boolean sort) throws Exception{
		HqlHelper hp = new HqlHelper();
		boolean needOrder = false;
		Map<String,String> om = new HashMap<String, String>(); // 包含or的
		// 值为空或""的去掉,并处理有or条件的
		Map<String,String> map = new HashMap<String,String>();
		for(Map.Entry<String, String> et: mapKv.entrySet()) {
			if(et.getValue()!=null&&et.getValue()!="") {
				if(et.getKey().equals("sort_name")||et.getKey().equals("sort_order")||et.getKey().equals("a.sort_name")||et.getKey().equals("a.sort_order")) {
					needOrder = true;
					continue; // 排序字段
				} 
				if(et.getKey().contains("__or")) {
					om.put(et.getKey(), et.getValue());
				} else {
					map.put(et.getKey(), et.getValue());
				}
			}
		}
		
		StringBuffer sb = new StringBuffer(fromObject + " a where 1=1");
		boolean leftk = false;
		if(map.size() > 0) {
			// 1. 特殊字符
			Pattern kr = Pattern.compile("[\\*\\!,\\^\\$\\{\\(\\]\\`\\~\\#\\/\\\\%@\\s]");
			Pattern vr = Pattern.compile("[\\*\\?=%]");
			for(Map.Entry<String, String> et: map.entrySet()) {
				if(kr.matcher(et.getKey()).find())throw new Exception("字段名包含特殊符号!");
				if(vr.matcher(et.getValue()).find())throw new Exception("值包含特殊符号!");
			}
			// 判断是否有不包含__or的
			if(om.size() != map.size()) {
				if(!leftk) {
					sb.append(" and ("); // 开始要加上括号,以便后面__or条件封装
					leftk = true;
				}
				boolean first = true; // 是否是第一个,第一个不需要用and,后面的都要用and
				for(Map.Entry<String, String> et: map.entrySet()) {
					if(et.getKey().contains("__or")) continue;
					if(et.getKey().contains("__gt")||et.getKey().contains("__lt")||et.getKey().contains("__in")
							||et.getKey().contains("__contains")||et.getKey().contains("__startwith")||et.getKey().contains("__endwith")) { // 非等于关系
						if(first) {
							first = false;
							sb.append("a.").append(et.getKey().split("__")[0]).append(" ");
							
						} else {
							sb.append(" and a.").append(et.getKey().split("__")[0]).append(" ");
						}
						// 关系 + 值
						if (et.getKey().split("__")[1].replace("__", "").equals("gt")) {
							sb.append(">").append(" ").append("'"+et.getValue() + "'");
						} else if (et.getKey().split("__")[1].replace("__", "").equals("gte")) {
							sb.append(">=").append(" ").append("'"+et.getValue() + "'");
						} else if (et.getKey().split("__")[1].replace("__", "").equals("lt")) {
							sb.append("<").append(" ").append("'"+et.getValue()+"'");
						} else if (et.getKey().split("__")[1].replace("__", "").equals("lte")) {
							sb.append("<=").append(" ").append("'"+et.getValue()+"'");
						} else if (et.getKey().split("__")[1].replace("__", "").equals("in")) {
							sb.append("in (").append(et.getValue()).append(")");
						} else if (et.getKey().split("__")[1].replace("__", "").equals("contains")) {
							sb.append("like").append(" '%").append(et.getValue()).append("%'");
						} else if (et.getKey().split("__")[1].replace("__", "").equals("startwith")) {
							sb.append("like '").append(et.getValue()).append("%'");
						} else if (et.getKey().split("__")[1].replace("__", "").equals("endwith")) {
							sb.append("like ").append("'%").append(et.getValue() + "'");
						} else if (et.getKey().split("__")[1].replace("__", "").equals("startwith")) {
							sb.append("like '").append(et.getValue()).append("%'");
						}
					} else { // 等于关系
						if(first) {
							first = false;
							sb.append("a.").append(et.getKey()).append("='").append(et.getValue()+"'");
						} else {
							sb.append(" and a.").append(et.getKey()).append("='").append(et.getValue()+ "'");
						}
					}
				}
				sb.append(")");
			}
		}
		if(needOrder) {
			sb.append(" order by ").append(mapKv.get("sort_name")==null?mapKv.get("a.sort_name"):mapKv.get("sort_name")).append(" ");
			if(mapKv.get("sort_order")!=null||mapKv.get("a.sort_order")!=null) {
				sb.append((mapKv.get("sort_order")==null?mapKv.get("a.sort_order"):mapKv.get("sort_order")).replace("ending", ""));
			} else {
				sb.append("asc");
			}
		}
		hp.setOrMap(om);
		hp.setHql(sb.toString().replaceAll("a\\.a\\.", "a."));
		System.out.println(hp.getHql());
		return hp;
	}
	
}

  

posted @ 2020-09-14 23:13  trump2  阅读(302)  评论(0)    收藏  举报