HQL伪代码解析算法(易扩展)


解析的语法规则:

$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 );
	}  
}


你可能感兴趣的:(算法,Access)