这个文章是我写的第一篇文章,可能比较小白... .
我们可能遇见一些前台需要Ajax调用后台java方法,然后大多数情况下是java实现业务逻辑,当然主要是写sql ..
最近在项目中就遇见这么一个问题.
项目A需要调用项目B提供的函数返回结果集.(A和B不同域)
所以可以用Ajax+servlet实现. 但是考虑扩展性,复用性. 这个方式不是很好.
我的想法是servlet或者后台java方法是和具体的业务逻辑实现无关的. 也就是把业务实现层(大多数是sql)抽离出来.
java只负责实现配置出的sql,然后返回给前台.
怎么做到无关. 还是靠xml -.- 这不是废话么..
现在看看我们需要什么..
1. 我们需要一块内存存放xml配置的文件. 这块内存是跟web容器生命周期一样的. web容器一启动就初始化.
2. 还要处理前台传来的参数的servlet或者方法.
3. 还要把前台传入的参数和xml配置好的sql 进行关联. (也就是把sql配置中的变量进行赋值,当然这里还会有一些解析的工作)
在这个项目中,传递参数,主要用json. 因为json与javascript结合的比较好,而且相对于xml,json是轻量级的.(单从传递字符串大小来说)
所以还要处理后台解析json-->对象. 和查询完成之后 java对象-->json 的过程.
好了 我们需要这些东西. 东西准备好了. 我们要设计流程了.
不知道大家玩过crazy Machines 没有. 里面会给你所用到的所有设备,你需要实现流程.
现在我们有了这些功能点,我们需要把这些功能点组成我们希望的结果.
我先说下大体的流程.
容器加载流程. 加载完成以后, 我们的xml文件就在内存当中了. (这个内存在本项目中用map实现的)
web容器启动--> 读取web.xml文件-->加载我们在web.xml配置好的监听-->监听就做一件事,把我们配置好的xml文件加载到map当中.
前台请求流程.
前台发送请求给servlet或者jsp-->依据传入的查询ID,去找map中配置好的sql对象-->把其他入参解析为对象.--> 把sql对象和入参的对象进行比对.-->如果传入的对象名称和sql对象中的变量name一致,就把sql对象的变量赋值. -->执行处理好的sql-->返回对象-->解析为json字符-->返回给前台.
过程比较简单. 下面就把主要的文件以伪代码的形式粘出来,仅供参考.
ContextLoaderListener.java //这个文件是需要配置在web 中的
比如 :
<listener>
<listener-class>com.yourcompany.ContextLoaderListener</listener-class>
</listener>
其实这个listener就是为了在web容器启动的时候来加载这个ContextLoaderListener的.
ContextLoaderListener 具体内容:
public class ContextLoaderListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
XMLDispatchReader d=new XMLDispatchReader();
d.loadDispatchDefinitions(sce.getServletContext());
}
public void contextDestroyed(ServletContextEvent sce) {
}
}
我们需要实现ServletContextListener接口 然后实现接口里面的两个方法: contextInitialized,contextDestroyed..
contextInitialized web容器初始化的时候执行.
contextDestroyed web容器销毁的时候执行.
具体的可以google下.
这里面的 XMLDispatchReader是用于解析xml文件的. 解析xml文件就不在这里赘述了.
我附上xml配置文件中的一个查询实例 (我把对xm的说明也粘一下吧 )
<!--
说明:
1. 在 /~ ~/ 标记里面的内容会和前台传来的json 对象参数 进行比对.
如果有 会把/~ ~/ 里面的内容填充
比如:
/~ resTypeId : and a.res_Type_Id= {string} ~/
如果json 对象里面有 "resTypeId":"12212344"
转义之后为
and a.res_Type_Id='12212344'
如果 是
/~ resTypeId : and a.res_Type_Id= {number} ~/
转义之后为
and a.res_Type_Id=12212344
2.if 和else 的使用.
在if条件满足的时候, 会自动过滤if后面跟的第一个else .如果多个if 连在一起 会一个一个判断
注意 if和( ,else和[ 没有空格 == 后面的属性值 没有" 或者'
目前 只支持一层查询.. if()[] else[] 不支持嵌套if else
比如:
if(resTypeId==23000203)[ /~ resTypeId : and a.res_Type_Id= {string} ~/ ]
else[ /~ resTypeId : and a.res_Type_Id= {string} ~/ ]
会和传来的resTypeId参数进行比对 如果 resTypeId ==23000203 会留下If后面[]里面的语句.
如果条件为false 会自动留下else里面的sql
-->
<map queryId="10000001" >
<queryDescription>测试查询</queryDescription>
<sql sqlType="select" retParName="resId,resName" >
select * from dual
</sql>
</map>
这里我们针对xml需要建立一个描述xml文件的对象和保存这个对象所需要的一块内存.
需要建立两个类.
DispatchInfoFactory.java
这个类 很简单.
protected Map dispatchMap;
private static final DispatchInfoFactory dispatchFactorySingleton = new DispatchInfoFactory();
private DispatchInfoFactory() {
dispatchMap = new HashMap();
}
public static DispatchInfoFactory getInstance() {
return dispatchFactorySingleton;
}
public Object get(String key) {
return dispatchMap.get(key.toUpperCase());
}
public void putAll(Map map) {
dispatchMap.putAll(map);
}
public int size() {
return dispatchMap.size();
}
只有获取类的实例等方法.
DispatchInfo.java
这个类就是对xml对象的描述. 这里就不写了.
XMLDispatchReader 的目的在于解析xml 把xml的queryId作为key 存在map中
类似与 (伪代码)
Map map=null;
DispatchInfo dispatchInfo=null;
while(node != null){
dispatchInfo=new DispatchInfo();
dispatchInfo.setQueryId(node.queryId);
.....
map.put(dispatchInfo.getQueryId,dispatchInfo);
}
DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance();
domfac.putAll(map);
好了 现在我们已经在web.xml 中配置了一个监听,用于初始化存放xml配置文件的内存.