HQL伪代码解析算法(易扩展)
程序员文章站
2022-07-02 19:22:02
...
解析的语法规则:
$req{key}$:
典型应用:
1.表示从 当前的requset中 获取数据 key为获取数据的键值.
$sen{key}$
典型应用:
1. $sen{User}$ 表示 从当前session中获取User对象的Id.
2. $sen{User.id}$ 与上面是等价的.
3. $sen{User.userName}$ 表示 从当前session中获取User对象的 用户名
4. $sen{User.field1.field2.fieild...n} 深层属性取值的时候.
$date{day,format}$
典型应用:
1. $date{3}$ 表示获取前三天的时间点 , 默认第二个参数可以不写 默认为:yyyy-MM-dd
2. $date{current}$ 获取当前时期 :默认格式为:yyyy-MM-dd
$time{hour,format}$
典型应用:
1. $time{8}$ 表示获取前8小时的时间点,第二个参数可以不写:默认格式为:yyyy-MM-dd HH:mm:ss
2. $time{current}$ 获取当前时间 :默认格式为:yyyy-MM-dd HH:mm:ss
以下为代码示例:
$req{key}$:
典型应用:
1.表示从 当前的requset中 获取数据 key为获取数据的键值.
$sen{key}$
典型应用:
1. $sen{User}$ 表示 从当前session中获取User对象的Id.
2. $sen{User.id}$ 与上面是等价的.
3. $sen{User.userName}$ 表示 从当前session中获取User对象的 用户名
4. $sen{User.field1.field2.fieild...n} 深层属性取值的时候.
$date{day,format}$
典型应用:
1. $date{3}$ 表示获取前三天的时间点 , 默认第二个参数可以不写 默认为:yyyy-MM-dd
2. $date{current}$ 获取当前时期 :默认格式为:yyyy-MM-dd
$time{hour,format}$
典型应用:
1. $time{8}$ 表示获取前8小时的时间点,第二个参数可以不写:默认格式为:yyyy-MM-dd HH:mm:ss
2. $time{current}$ 获取当前时间 :默认格式为:yyyy-MM-dd HH:mm:ss
以下为代码示例:
public class DynHqlUtil {
/**
* hql语句装配 将伪代码转化为可执行代码
*
* @param hql
* @return
* @throws Exception
*/
public static String hqlLoader(String hql) throws Exception{
DynHqlConfig cfg = new DynHqlConfig();
DynHqlLoader loader = new DynHqlLoader();
return loader.loader(hql, cfg);
}
public static void main(String[] args) {
String hql;
try {
hql = DynHqlUtil.hqlLoader("from User where xxx = $date{7}$ and bb='k' and kk=$date{current}$");
System.out.println( hql );
} catch (Exception e) {
e.printStackTrace();
}
}
}
/***************************************************************************/
public class DynHqlConfig {
public static final char BOR = '$'; //$...$ 定义边框
public static final char LEFTSIGN = '{';// 左 括 弧
public static final char RIGHTSIGN = '}';// 右 括 弧
public static final String REQ = "req";//$req{key}$ 定义HttpRequest
public static final String SEN = "sen";//$sen{key}$ 定义HttpSession
public static final String DATE = "date";//$date{day,format}$ 定义日期
public static final String TIME = "time";//$time{hour}$ 定义时间
public static final String DATE_CURRENT ="current";//定义 本地当前时间
private Map<String,String> mapKey;
public DynHqlConfig(){
//此处重定义 伪代码key值
mapKey = new HashMap<String, String>();
mapKey.put("user",Constants.USER_AUTH);//定义取用户的 key值
}
public String getKey( String contentKey ) {
String key = contentKey.trim().toLowerCase();
if( !mapKey.containsKey(key) )
return key;
return mapKey.get(key);
}
}
/*******************************************************************************/
@SuppressWarnings("unused")
public class DynHqlLoader {
static char[] hex = "0123456789ABCDEF".toCharArray();
private StringBuilder buf ;
private DynHqlConfig cfg ;
private int startInx = 0;
private int endInx = -1;
//边框 开始与结束
private boolean borStar = false;
private boolean borEnd = false;
//大括弧 开始与结束
private boolean bracStar = false;
private boolean bracEnd = false;
/**
* 装配 hql 语句
* @param hql
* @param cfg
* @return
* @throws Exception
*/
public String loader(String hql , DynHqlConfig cfg) throws Exception{
this.cfg = cfg;
this.buf = new StringBuilder();
this.parseHql(hql);
return buf.toString();
}
/**
* 解析 hql
* @param hql
* @throws Exception
*/
@SuppressWarnings("static-access")
private void parseHql(String hql) throws Exception{
int length = hql.length();
String str = "";
CharacterIterator it = new StringCharacterIterator(hql);
boolean sbor = false;
boolean ebor = false;
int inx = -1;
for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
endInx++;//实时记录 当前处理的下标
//当遇到第一个 $符号时 开始进入等待下一个对称$ 结束符的出现 否则视为语法错误 原样输出
if( c == cfg.BOR ){
if( sbor && !ebor ) ebor =true;
if( !sbor ){
sbor = true;
this.appendHql(hql);
}
}
if(sbor && ebor){
sbor = ebor = false ;
this.appendFakcCode(hql);
}
}
String h = hql.substring(this.startInx,length);
this.buf.append(h);
}
/**
* 拼接 非动态部分 hql
* 调整索引下标
* @param hql
*/
private void appendHql(String hql){
String h = hql.substring(this.startInx,this.endInx);
this.buf.append(h);
this.startInx = this.endInx;
}
/**
* 处理 动态部分 hql
* 调整索引下标
* @param hql
*/
@SuppressWarnings("static-access")
private void appendFakcCode(String hql) throws Exception{
String fcode = hql.substring(this.startInx,this.endInx+1);
this.startInx = this.endInx+1;
String value = fcode;
System.out.println("之前:fcode "+value);
if( this.validBracket(fcode) ){
if(fcode.indexOf(cfg.REQ )!=-1){
value = this.request(fcode);
}else if(fcode.indexOf(cfg.SEN )!=-1){
value = this.session(fcode);
}else if(fcode.indexOf(cfg.DATE )!=-1){
value = this.date(fcode);
} else if(fcode.indexOf(cfg.TIME)!=-1){
value = this.time(fcode);
}
}
System.out.println("之后:fcode "+value);
this.buf.append(value);
}
/**
* 从 HttpRequest 中取值
*/
@SuppressWarnings("static-access")
private String request(String fcode){
Object value = fcode;
String[] params = null;
String key = fcode.substring( fcode.indexOf(cfg.LEFTSIGN)+1,fcode.indexOf(cfg.RIGHTSIGN) );
if(key!=null){
params = (String[])ServletActionContext.getContext().getParameters().get(key.trim());
if( params!=null && params.length>=1 ){
value = params[0];
}
}
return value.toString();
}
/**
* 从 HttpSession 中取值
*/
@SuppressWarnings("static-access")
private String session(String fcode)throws Exception{
String value = fcode;
String content = fcode.substring( fcode.indexOf(cfg.LEFTSIGN)+1,fcode.indexOf(cfg.RIGHTSIGN) );
Object obj = null;
String key = null;
if(content!=null){
//假设 单对象的情况
if( content.indexOf(".")==-1 ){
key = cfg.getKey(content);
if( key!=null )
obj = ServletActionContext.getContext().getSession().get( key );
if( obj != null && key != null ){
String methodName = "getId";
if( methodName!=null )
value = (String)obj.getClass().getMethod( methodName ).invoke(obj);
}
}
//假设 对象.属性的情况
if( content.indexOf(".")!=-1 ){
String[] prop = content.split("\\.");
key = cfg.getKey(prop[0]);
if( key!=null )
obj = ServletActionContext.getContext().getSession().get( key );
if( obj != null && key != null ){
//截取 属性链 (将属性链的第一个去掉)
String nextPropLink = content.substring(content.indexOf(".")+1,content.length());
value = this.getParameter(obj,nextPropLink);
}
}
}
return value ;
}
private String getParameter(Object obj , String propLink ) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
System.out.println( propLink );
String[] fields = propLink.split("\\.");
String fieldName = null;
String nextPropLink = null;
boolean exeRecursion = true; //是否继续执行递归
if( fields.length == 1 ){
exeRecursion = false;
fieldName = fields[0];
}
if( fields.length > 1 ){
exeRecursion = true;
fieldName = propLink.substring(0,propLink.indexOf("."));
nextPropLink = propLink.substring(propLink.indexOf(".")+1,propLink.length());
}
BeanInfo info = Introspector.getBeanInfo(obj.getClass());
PropertyDescriptor[] props = info.getPropertyDescriptors();
Object value = obj;
for (int i = 0; i < props.length; i++) {
PropertyDescriptor prop = props[i];
String name = prop.getName();
if( !name.equals( fieldName ) ){
continue;
}
Method method = prop.getReadMethod();
value = method.invoke(obj, new Object[0]);
if(exeRecursion)
return this.getParameter(value, nextPropLink);
else
break;
}
return value.toString();
}
/**
* 获取相对 日期-时间
*
* 解析格式 : $date{day,format}$ 第2个参数可不指定 默认为:默认时间格式:yyyy-MM-dd
* 默认格式 : $date{current}$ 默认时间格式:yyyy-MM-dd
* @param value
* @return
* @throws Exception
*/
@SuppressWarnings("static-access")
private String date(String fcode) throws Exception{
String content = fcode.substring( fcode.indexOf(cfg.LEFTSIGN)+1,fcode.indexOf(cfg.RIGHTSIGN) );
String value = fcode ;
if(content!=null){
String[] args = content.split(",");
if(args.length==2){
//获取当前日期 $date{current,yyyy-MM-dd HH:mm:ss}$
if( content.indexOf( cfg.DATE_CURRENT )!=-1 ){
value = this.date(0,args[1]);;
} else {//获取指定的相对日期 $date{7,yyyy-MM-dd HH:mm:ss}$
int day = -1;
if( (day = this.validNumber(args[0]) )!=-1 ){
value = this.date(day,args[1]);
}
}
}
if(args.length==1){
//获取当前日期 $date{current}$
if( content.indexOf( cfg.DATE_CURRENT )!=-1 ){
value = this.date(0,"yyyy-MM-dd");;
} else {//获取指定的相对日期 $date{7}$
int day = -1;
if( (day = this.validNumber(args[0]) )!=-1 ){
value = this.date(day,"yyyy-MM-dd");
}
}
}
}
return value;
}
/**
* 获取 指定的相对时间( 日期-时间 )
*
* @param number
* @return
* @throws Exception
*/
private String date(int number,String format) throws Exception{
long l = System.currentTimeMillis();
long subDay = (24L*60L*60L*1000L)*(long)number;
return DateUtil.getAppointTime( (l-subDay) ,format);
}
/**
* 获取相对 时间(小时)
*
* 解析格式 : $time{hour,format}$ 第2个参数可不指定 默认为:默认时间格式:yyyy-MM-dd HH:mm:ss
* 默认格式 : $time{current}$ 默认时间格式:yyyy-MM-dd HH:mm:ss
* @param fcode
* @return
* @throws Exception
*/
@SuppressWarnings("static-access")
private String time(String fcode)throws Exception{
String content = fcode.substring( fcode.indexOf(cfg.LEFTSIGN)+1,fcode.indexOf(cfg.RIGHTSIGN) );
String value = fcode ;
if(content!=null){
String[] args = content.split(",");
if(args.length==2){
//获取当前日期 $date{current,yyyy-MM-dd HH:mm:ss}$
if( content.indexOf( cfg.DATE_CURRENT )!=-1 ){
value = this.time(0,args[1]);
} else {//获取指定的相对日期 $date{7,yyyy-MM-dd HH:mm:ss}$
int hour = -1;
if( (hour = this.validNumber(args[0]) )!=-1 ){
value = this.time(hour,args[1]);
}
}
}
if(args.length==1){
//获取当前日期 $date{current}$
if( content.indexOf( cfg.DATE_CURRENT )!=-1 ){
value = this.time(0,"yyyy-MM-dd HH:mm:ss");
} else {//获取指定的相对日期 $date{7}$
int hour = -1;
if( (hour = this.validNumber(args[0]) )!=-1 ){
value = this.time(hour,"yyyy-MM-dd HH:mm:ss");
}
}
}
}
return value;
}
/**
* 获取 相对时间 (小时)
* @param hour
* @param format
* @return
* @throws Exception
*/
private String time(int hour,String format)throws Exception{
long l = System.currentTimeMillis();
long subHour = (60L*60L*1000L)*(long)hour;
return DateUtil.getAppointTime(l-subHour,format);
}
/**
* 验证 括弧的合法性
* @return
*/
@SuppressWarnings("static-access")
private boolean validBracket(String fakcCode){
String fcode = fakcCode;
boolean bool = false ;
if( (fcode.indexOf(cfg.LEFTSIGN)!=-1) && (fcode.indexOf(cfg.RIGHTSIGN)!=-1)){
bool = true ;
}
return bool;
}
/**
* 验证是否是 数字字符
* @param strNumber
* @return
*/
private int validNumber(String strNumber){
String strNum = strNumber.trim();
int ascall = -1;
if(strNum!=null&&!"".equals(strNum)){
for (int i = 0; i < strNum.length(); i++) {
ascall = strNum.charAt(i);
if(ascall<'0'|| ascall>'9') return -1;
}
}
return Integer.parseInt( strNum );
}
}
推荐阅读