六、配置ibatis
接下来,使用ibatis实现o/r mapping。首先从http://www.ibatis.com下载ibatis 2.0,将所需的jar文件复制到web/web-inf/lib/目录下。ibatis使用xml配置数据库表到java对象的映射,先编写一个sql-map-config.xml:
<?xml version="1.0" encoding="utf-8" ?>
<!doctype sqlmapconfig
public "-//ibatis.com//dtd sql map config 2.0//en"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlmapconfig>
<settings cachemodelsenabled="false" enhancementenabled="true"
lazyloadingenabled="true" maxrequests="32"
maxsessions="10" maxtransactions="5"
usestatementnamespaces="false"
/>
<transactionmanager type="jdbc">
<datasource type="jndi">
<property name="datasource" value="jdbc/blog" />
</datasource>
</transactionmanager>
<!-- 如果有其他xml配置文件,可以包含进来 -->
<sqlmap resource="account.xml" />
</sqlmapconfig>
将sql-map-config.xml放到web/web-inf/classes/目录下,ibatis就能搜索到这个配置文件,然后编写一个初始化类:
public class sqlconfig {
private sqlconfig() {}
private static final sqlmapclient sqlmap;
static {
try {
java.io.reader reader = resources.getresourceasreader ("sql-map-config.xml");
sqlmap = sqlmapclientbuilder.buildsqlmapclient(reader);
} catch (exception e) {
e.printstacktrace();
throw new runtimeexception("error initializing sqlconfig. cause: " + e);
}
}
public static sqlmapclient getsqlmapinstance () {
return sqlmap;
}
}
sqlmapclient封装了访问数据库的大部分操作,可以直接使用sqlconfig.getsqlmapinstance()获得这个唯一实例。
七、使用dao模1式
为了分离逻辑层和数据库持久层,定义一系列dao接口:accountdao,categorydao,articledao……其实现类对应为sqlmapaccountdao,sqlmapcategorydao,sqlmaparticledao……这样就使得逻辑层完全脱离了数据库访问代码。如果将来需要使用其它的o/r mapping方案,直接实现新的dao接口替代现有的sqlmapxxxdao即可。以sqlmapaccountdao为例,实现一个login()方法是非常简单的:
public int login(string username, string password) throws authorizationexception {
try {
map map = new hashmap();
map.put("username", username);
map.put("password", password);
integer i = (integer)sqlmap.queryforobject("login", map);
if(i==null)
throw new runtimeexception("failed: invalid username or password.");
return i.intvalue();
}
catch(sqlexception sqle) {
throw new runtimeexception("sql exception: " + sqle);
}
}
在account.xml配置文件中定义login查询:
<select id="login" parameterclass="java.util.map" resultclass="int">
select [accountid] from [account] where
[username] = #username# and password = #password#
</select>
八、逻辑层设计
由于dao模式已经实现了所有的数据库操作,业务逻辑主要是检查输入,调用dao接口,因此业务逻辑就是一个简单的facade接口:
public class facadeimpl implements facade {
private accountdao accountdao;
private articledao articledao;
private categorydao categorydao;
private feedbackdao feedbackdao;
private imagedao imagedao;
private linkdao linkdao;
private sequencedao sequencedao;
}
对于普通的getarticle()等方法,facade仅仅简单地调用对应的dao接口:
public article getarticle(int articleid) throws queryexception {
return articledao.getarticle(articleid);
}
对于需要身份验证的操作,如deletearticle()方法,facade需要首先验证用户身份:
public void deletearticle(identity id, int articleid) throws deleteexception {
article article = getarticleinfo(articleid);
if(article.getaccountid()!=id.getaccountid())
throw new authorizationexception("permission denied.");
articledao.deletearticle(articleid);
}
要分离用户验证逻辑,可以使用proxy模式,或者使用spring的aop,利用methodinterceptor实现,不过,由于逻辑很简单,完全可以直接写在一块,不必使用过于复杂的设计。 至此,我们的blog已经实现了所有的后台业务逻辑,并且提供统一的facade接口。前台web层仅仅依赖这个facade接口,这样,web层和后台耦合非常松散,即使替换整个web层也非常容易。
九、web层设计:使用mvc模式
对于复杂的web层,使用mvc模式是必不可少的。虽然spring能轻易集成struts,webworks等web框架,但spring本身就提供了一个非常好的web框架,能完全实现mvc模式。
spring使用一个dispatcherservlet,所有的特定请求都被转发到dispatcherservlet,然后由相应的controller处理,controller返回一个modelandview对象(因为java语言的方法调用只能返回一个结果,而且不支持ref参数,所以将model和view对象合在一起返回),model是一个java对象,通常是map,view是视图的逻辑名字,通常是jsp文件名,但也可以使用velocity等作为视图。返回的view通过viewresolver得到真正的文件名。首先配置spring的mvc,在web.xml中声明dispatcherservlet,处理所有以.c结尾的请求:
<web-app>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.c</url-pattern>
</servlet-mapping>
</web-app>
spring会在web-inf下查找一个名为dispatcher-servlet.xml的文件,我们需要创建这个文件:
<?xml version="1.0" encoding="utf-8"?>
<!doctype beans public "-//spring//dtd bean//en"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
</beans>
用到的所有的java bean组件都要在这个文件中声明和配置,以下是配置url映射的bean:
<bean id="urlmapping"
class="org.springframework.web.servlet.handler.simpleurlhandlermapping">
<property name="mappings">
<props>
<prop key="/article.c">articlecontroller</prop>
</props>
</property>
</bean>
凡是匹配/article.c的request都会被名为articlecontroller的bean处理,同样需要声明这个articlecontroller:
<bean id="articlecontroller" class="example.viewarticlecontroller">
</bean>
viewarticlecontroller处理请求,然后生成model,并选择一个view:
public class viewarticlecontroller implements controller {
private facade facade;
public void setfacade(facade facade) { this.facade = facade; }
public modelandview handlerequest(httpservletrequest request,
httpservletresponse response) throws exception {
// 获得参数:
int articleid = integer.parseint(request.getparameter("articleid"));
// 使用facade处理请求:
article article = facade.getarticle(articleid);
// 生成model:
map map = new hashmap();
map.put("article", article);
// 返回model和视图名“skin/blueskysimple/article”:
return new modelandview("skin/blueskysimple/article", map);
}
}
最后,skin/bluesky/article视图会将结果显示给用户。
我们注意到,viewarticlecontroller并不自己查找或者创建facade,而是由容器通过setfacade(facade)方法设置的,这就是所谓的ioc(inversion of control)或者dependency injection。容器通过
闽公网安备 35060202000074号