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;
}
}
无聊我就学英语

浙公网安备 33010602011771号