服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

基于 j2ee 体系实现多层结构 blog 平台(2)


  六、配置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。容器通过

扫描关注微信公众号