MVC模式的设计思想

 

MVC模式的设计思想

MVC模式是一种近年来使用比较广泛的为许多IT厂家和开发者所认可的一种设计模式,它和Web应用程序并没有直接的关系(事实上,它在很多非WEB应用程序中得到了使用),它不仅使得系统层次分明、职责清晰,而且使得系统更易于维护。在MVC模式中的三个关键部件及其主要功能职责是:

The Model Component:主要负责业务域的业务目标的实现。

The View Component:主要负责对业务域的数据展现给客户端。

The Controller Component:主要负责控制系统流程和用户输入状态

在基于Java技术的Web应用程序中,Model部分的主要组件是JavaBeanEJBView部分的主要组件是HTMLJSP程序,Controller部分的主要组件是Servlet部分。

下面列出了一些使用MVC模式的好处:

1、        它将业务逻辑与展现分离开来,避免了将业务逻辑与展现混杂在一起带来的显示的不一致性和业务逻辑代码重复地分布在用于展现的代码中。

2、        层次清晰,易于开发者对这三个部分分工与协作,易于维护者识别不同的层次实施不同的维护策略。

3、        系统具有更好的重用性,包括用户界面的重用和业务逻辑处理包的重用,特别是业务逻辑处理包,如果遵循相应的java规范,它不仅可以在web应用程序中使用,而且可以在包括桌面、分布式环境下的得到重用。

4、        系统更易于扩展和移植。

5、        系统更易于维护。

6、        采用MVC模式开发的系统更健壮。

7、        对于大型的应用程序优势更为明显。

 

谈到设计模式,可以想一下我们常用的jsp+beanjsp+servlet+bean的模式

JSP Model1

JSP Model2

上图中,JSP Model1JSP+JavaBean的模式,在这种模式下,处理客户端的请求和将输出展现给客户端都是由JSP页面负责的,在模式1中,整个过程没有Servlet的参与,它将主要的业务逻辑放到JavaBean中实现,而将页面展现和请求控制交给JSP处理。

不可否认jsp的开发模式简化了开发Web应用程序的复杂度,但是其缺点是显而易见的,由于jsp是在html中嵌入java代码的方式实现的,不可避免地,它也面临很多问题:如页面展现与业务逻辑混合在一起,仍然无法在开发过程中将不同的角色更清晰地区分开来;jsp页面中将会夹杂大量的java代码,维护变得困难;同时,业务逻辑的改动也将面临动一发而影响全局的窘境。

JSP Model2JSP+Servlet+JavaBean的模式,它和模式1的最大不同是它多了Servlet层,用于控制用户的请求和将JavaBean的业务输出传递给JSP来展现,这样就将数据展现、业务控制、业务逻辑实现分离开来,这就是早期的MVCModelViewControl)模式。显然,这种模式相对于jsp+bean的模式来说应用程序更具扩展性和灵活性,并且更易于维护。但是这种简单的MVC模式也有缺点,第一、没有成熟的MVC框架中所带有的各种强大和实用的功能,第二、配置文件不好管理,成熟的MVC框架支持多配置文件,而servlet的配置都写在web.xml中,这会导致web.xml文件难以管理。因此有必要掌握一种成熟的MVC的开发框架。

对于现有较成熟的Model-View-Control(MVC)框架而言,其解决的主要问题有下面几部分:

1. 将Web页面中的输入元素封装为一个(请求)数据对象。

2. 根据请求的不同,调度相应的逻辑处理单元,并将(请求)数据对象作为参数传入。

3. 逻辑处理单元完成运算后,返回一个结果数据对象。

4. 将结果数据对象中的数据与预先设计的表现层相融合并展现给用户。

 

数据封装和持久性

       MVC的设计思想中,数据在不同层之间的传递是以数值对象的形式进行封装的,这里的数值对象是指不同层之间传输数据的容器,在不同的层中数据的传输应该封装在数值对象中(不可能把resultSet对象用于各层数据的传递,这有背于MVC的设计思想),这样能够提高网络传输效率(减少传输次数),同时使得维护更方便。

通常数值对象就是一个Bean,它对数据库中的表或视图的字段进行了封装,一个数值对象可以看成表或视图中的一条记录。

       一个简单的数据对象

public class User{

  private String bh;

  private String name;

  public String getName() {

    return name;

  }

  public String getBh() {

    return bh;

  }

  public void setName(String name) {

    this.name = name;

  }

  public void setBh(String bh) {

    this.bh = bh;

  }

  public User() {

  }

}

通常我们会这样做,

控制器在接收提交请求后将request对象中提交过来的数据封装在User的实例中

User user = new User();

user.setBh(request.getParameter(“bh”));

user.setName(request.getParameter(“Name”));

然后将该数据对象作为参数传递给逻辑Bean或直接用数据访问对象来执行业务操作,

UserDAO userDAO = new UserDAO();

userDAO.insertUser(user);

      

       User user = userDAO.getUser(request.getParameter(“bh”));

    List userList = userDAO.getUserList();

数据底层的访问在UserDAO中进行,打开数据连接connection,查询得到结果集resultset将数据封装在User的实例中,关闭连接返回数值对象,或者调用statement对象进行更新操作。操作完毕后由控制器将获取的数值对象发往页面。

  public User getUser(String id)throws SQLException{

    Connection conn = null;

    try{

      conn = this.ds.getConnection();

      Statement stmt = conn.createStatement();

      ResultSet rs = stmt.executeQuery("select * from user where id='" + id +"'");

      User user = null;

      if (rs.next()) {

        user = new User();

        user.setBh(rs.getString("bh"));

        user.setBh(rs.getString("name"));

      }

      return user;

    }

    finally{

      conn.close();

    }

  }

对于单条记录用user对象实例封装,那么对于多条记录集则是以List集合的形式进行封装,List集合中的每个对象就是一个user对象实例,

  public List getUserList() throws SQLException {

    Connection conn = null;

    try {

      conn = this.ds.getConnection();

      Statement stmt = conn.createStatement();

      ResultSet rs = stmt.executeQuery("select * from user");

      List userList = new ArrayList();

      while (rs.next()) {

        User user = new User();

        user.setBh(rs.getString("bh"));

        user.setBh(rs.getString("name"));

        userList.add(user);

      }

      return userList;

    }

    finally {

      conn.close();

    }

  }

上面的例子只是说明了MVC模式中的数据封装的思想,如果按照上面的例子写,你会发现要写好多的数值对象来映射数据库的表,对于查询的得到的结果集都要手动进行封装,一旦数据库的表发生了变化,那么改起来将非常的繁琐,因此在实际运用中应该采取效率更高的数据封装办法,通过Map对象代替数值对象并配合合适的数据持久层的支持就可以达到数据封装的自动化,从而提高我们的开发效率。

综上所述,选择合适的MVC框架和数据持久层作为我们项目中的开发模式是很有必要的,通过对现在流行的MVC框架和数据持久层的了解,Spring+Ibatis的开发模式是很适合的一种。

Spring的优点

Spring提供了一套成熟而全面的基础框架,站在应用开发的实际角度来说,其最大的优势在于:Spring是一个从实际项目开发经验中抽取的,可高度重用的应用框架

Spring Framework中目前最引人注目的,也就是名为控制反转(IOC Inverse Of Control)或者依赖注入(DI Dependence Injection)的设计思想。

IoC,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中,实现了组件真正意义上的即插即用。这也是Spring最具价值的特性之一

但是,光一个单纯的设计模式并不能使得Spring如此成功,而Spring最成功的地方也并不仅仅在于采用了IOC/DI的设计。

首先,Spring涵盖了应用系统开发所涉及的大多数技术范畴,包括MVCORM以及RemoteInterface等,这些技术往往贯穿了大多数应用系统的开发过程。Spring从开发者的角度对这些技术内容进行了进一步的封装和抽象,使得应用开发更为简便。

其次,Spring并非一个强制性框架,它提供了很多独立的组件可供选择。

 

Spring的基本配置和基础对象使用方法

Ibatis的优点

Ibatis的基本配置和核心对象使用方法

IbatisSpring中的配置和运用

Jstl表现技术的运用

实例

    结合于SpringIbatis的实际运用我写了一个例子,例子中实现了一个简单的登录过程和一个订货单的主从表形式的增、删、改、查功能,以供大家参考。

       我使用了Spring中的AbstractController控制器作为整个程序的基本的控制器,之所以这样做是考虑到简单实用的目的,同时能够实现主从表形式的数据输入,对于事务管理直接用ibatis中提供的事务管理功能,jsp页面统一存放在WEB-INF/view/下面,这样可以防止用户直接通过地址栏来访问jsp页面,jsp页面上用到的js脚本都以js文件的形式include到页面中,对于页面上的数据都以jstl的标签来输出达到页面简洁的目的。

配置文件说明

/WEB-INF/web.xml文件

程序运行的主要配置文件,配置了各种系统变量,对spring的加载,日志的加载等等

 

/WEB-INF/applicationContext.xml文件

启动时由spring加载系统中用到的各种bean

 

/WEB-INF/main-config.xml文件

对系统管理模块中的请求/处理单元的配置

 

/WEB-INF/indent-config.xml文件

对订货单模块中的请求/处理单元的配置

 

/WEB-INF/sqlMapConfig.xml文件

Ibatis的核心配置文件

 

WEB-INF/classes/com/ user.xml文件

用户模块的sql语句的映射文件

 

WEB-INF/classes/com/ common.xml文件

公用模块的sql语句的映射文件

 

WEB-INF/classes/com/ indent.xml文件

订货单模块的映射文件

 

对于系统中用到的控制器,我首先对AbstractController进行了抽象,编写了SimpleController类,在SimpleController类中我加入了各控制器中都要用到的公用属性和公用的bean,并抽象出AbstractController

public abstract ModelAndView handleRequestInternal(HttpServletRequest request,

                                            HttpServletResponse response) throws Exception;方法

其它各模块则继承自SimpleController,实现该方法,这样就可以使用SimpleController类中的各种属性和方法。

 

程序运行的具体流程如下

首先访问站点的入口web/index.jsp文件

<%@ include file="/WEB-INF/view/inc/head.jsp" %>

<%-- Redirected because we can't set the welcome page to a virtual URL. --%>

 

<c:redirect url="/loginInit.do"/>

文件中首先include了对jstl标签库的引用/WEB-INF/view/inc/head.jsp文件

<%@ page session="true"%>

<%@ taglib prefix="spring" uri="/WEB-INF/spring.tld"%>

<%@ taglib prefix="c"   uri="/WEB-INF/c.tld" %>

<%@ taglib prefix="fmt" uri="/WEB-INF/fmt.tld" %>

 

<c:redirect url="/loginInit.do"/>标签是重定向标签,该标签发出请求动作/loginInit.doweb容器,web容器依据web.xml中定义的请求映射动作

  <servlet-mapping>

    <servlet-name>main</servlet-name>

    <url-pattern>*.do</url-pattern>

  </servlet-mapping>

将该动作交由main所定义的系统管理模块的引擎进行

<servlet>

    <servlet-name>main</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>/WEB-INF/main-config.xml</param-value>

    </init-param>

    <load-on-startup>1</load-on-startup>

  </servlet>

该引擎接收到请求动作后,将该动作分发至系统管理逻辑处理单元就是/WEB-INF/main-config.xml文件

  <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

    <property name="mappings">

      <props>

        <prop key="/loginInit.do">loginController</prop>

        <prop key="/loginSubmit.do">loginController</prop>

      </props>

    </property>

  </bean>

main-config.xml文件通过urlMapping中定义的请求动作与控制器的映射

<prop key="/loginInit.do">loginController</prop>

将动作交由loginController所定义的控制器处理

  <bean id="loginController" class="com.manage.LoginController">

    <property name="bean"><ref bean="bean"/></property>

    <property name="sqlMap"><ref bean="sqlMap"/></property>

    <property name="formView"><value>login</value></property>

    <property name="successView"><value>main</value></property>

    <property name="mainField">

      <list>

        <value>usercode</value>

        <value>password</value>

      </list>

    </property>

  </bean>

该控制器引用了applicationContext.xml文件中加载的beansqlMap实例

<property name="bean"><ref bean="bean"/></property>

<property name="sqlMap"><ref bean="sqlMap"/></property>

以及对控制器处理请求后返回的视图属性的定义

<property name="formView"><value>login</value></property>

<property name="successView"><value>main</value></property>

com.manage.LoginController控制器主要实现了

  public ModelAndView handleRequestInternal(HttpServletRequest request,

                                    HttpServletResponse response) throws Exception 方法,该方法主要是对请求动作进行处理并返回一个ModelAndView对象,ModelAndView类包含了逻辑单元返回的结果数据集和表现层信息

  public ModelAndView handleRequestInternal(HttpServletRequest request,

                                    HttpServletResponse response) throws Exception {

 

    log.info(request.getMethod());

    Map model = new HashMap();

    Map userForm =null;

    Map userInfo = null;

 

    if(isGet(request)){

      userForm =  new HashMap();

      userForm.put("usercode","A1118");

      userForm.put("password","123");

      model.put("userForm",userForm);

      return new ModelAndView(formView,model);

    }

    else{

      userForm = (Map)bean.fillMap(mainField, request);

      try{

        sqlMap.startTransaction();

        userInfo = (Map)sqlMap.queryForObject("user.selectUser", userForm.get("usercode"));

        sqlMap.commitTransaction();

      }

      finally{

        sqlMap.endTransaction();

      }

      if(userInfo == null){

        model.put("message", "没有找到该用户");

        model.put("userForm", userForm);

        returnView = formView;

      }

      else{

        model.put("message", "登录成功");

        model.put("userInfo", userInfo);

        returnView = successView;

        printMap(userInfo);

        request.getSession().setAttribute("userInfo", userInfo);

      }

      return new ModelAndView(returnView, model);

    }

  }

这里我是用一个控制器对登录的初始化动作和登录提交动作进行控制,通过

if(isGet(request))来区分,初始化动作中将用户信息封装在model中并通过

return new ModelAndView(formView,model);

formView是请求动作返回的视图,在配置文件中已经定义了

<property name="formView"><value>login</value></property>

model是返回的结果数据集

将返回的视图和数据集交由urlMappingurlMapping会根据applicationContext.xml中定义的

  <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>

    <property name="prefix"><value>/WEB-INF/view/</value></property>

    <property name="suffix"><value>.jsp</value></property>

  </bean>

 

viewResolver在返回的视图的字符串加上前缀/WEB-INF/view/和后缀.jsp,即

/WEB-INF/view/login.jsp

然后通过main的调度引擎返回到login页面

<%@ page contentType="text/html; charset=GBK" %>

<%@ include file="/WEB-INF/view/inc/head.jsp" %>

<html>

<head>

<title>

login

</title>

<%@ include file="/WEB-INF/view/inc/css-js.inc" %>

</head>

<body bgcolor="#ffffff">

<spring:message code="title"/>

<spring:message code="fff"/>

 

<form action="/loginSubmit.do" method="POST">

<table width="100%" height="100%">

  <tr>

    <td  align="center" valign="middle">

      <c:if test="${message!=null}">

        <h4><c:out value="${message}" /></h4><br>

      </c:if>

  用户编号:<input type="text" name="usercode" value="<c:out value="${userForm.usercode}"/>"/>

  <br/>

  用户密码:<input type="text" name="password" value="<c:out value="${userForm.password}"/>"/>

   <br/> <input type="submit" value="ok"/>

    </td>

  </tr>

</table>

</form>

</body>

</html>

Login页面上使用了jstl的标签进行输出。这样一个登录初始化的过程就完成,

登录提交的原理和登录初始化的运行原理一样,

在登录提交过程中我也是使用的com.manage.LoginController控制器,在提交过程中我通过

userForm = (Map)bean.fillMap(mainField, request);方式将页面提交过来的表单数据封装在

userForm中的(订货单模块中都是用bean.fillMapbean.fillMaps来封装请求参数的),,这里的mainField是一个字符串数组,由LoginController的父类SimpleController中定义,bean也是在SimpleController定义的

mainField的作用是设置表单提交过来的字段,通过在配置文件中定义,这样可以避免硬编码,

    <property name="mainField">

      <list>

        <value>usercode</value>

        <value>password</value>

      </list>

    </property>

Bean的作用是将请求的表单中的数据以keyvalue 形式封装在Map

在提交过程中我使用了ibatis中的核心组件sqlMap,也是在配置文件中定义的

<property name="sqlMap"><ref bean="sqlMap"/></property>

Sqlap的调用方法如下

      try{

        sqlMap.startTransaction();开启事务

        userInfo = (Map)sqlMap.queryForObject("user.selectUser", userForm.get("usercode"));

        sqlMap.commitTransaction();提交事务

      }

      finally{

        sqlMap.endTransaction();结束事务

      }

(Map)sqlMap.queryForObject("user.selectUser", userForm.get("usercode"));方法用于查询用户的信息,

user.selectUser”是对应于user.xml映射文件中的selectUsersql语句的映射,userForm.get("usercode")是输入的参数

  <select id="selectUser" parameterClass="java.lang.String" resultClass="java.util.HashMap">

    <![CDATA[

    select * from v_BsUserRole where userCode = #userCode#

    ]]>

  </select>

Id就是调用sql的引用名,

parameterClass是输入的参数

resultClass是返回的结果集封装的类

sqlMap.queryForObject会根据输入的sql的引用名来完成查询和数据封装工作,

如果找到记录,则封装在resultClass定义的对象中返回,没有找到则返回null

执行完毕后,LoginController会返回main页面或login页面。

整个程序中运行的流程大致相同,下面将对ibatis的使用进行说明

示例中我使用了以下几种查询和数据库的操作

 

l         查询订货单记录

查询单条记录在订货单修改时用到,类为

com.indent.IndentModController

订货单是主从表关系,因此需要配置主表查询语句和从表查询语句

sql的映射文件为indent.xml文件

<select id="getIndent" parameterClass="java.lang.String" resultClass="java.util.HashMap">

  <![CDATA[

    select sellID, sellIDShow, dealerCode, dealerName, orderCode, orderName, orderDate,

    sumSellNum, sumFeeSell, source, sourceExplain, status, statusExplain,remark

    from V_OS_Sell where sellID = #sellID#

  ]]>

</select>

<select id="getIndentList" parameterClass="java.lang.String" resultClass="java.util.HashMap">

  <![CDATA[

    select partCode, partName, unit, priceSell, numStorage, orderNum, orderSum

    from V_OS_SellList where sellID = #sellID#

  ]]>

</select>

Id:程序中对sql的引用名

parameterClass:输入参数,

resultClass:封装每条记录的类

对于查询一条记录时ibatis直接返回resultClass中定义的封装数据的对象

对于查询多条记录,ibatis会将每条记录封装在resultClass定义的对象实例中然后将所有这所对象封装在List中返回

    Map indent = null;

    List indentList = null;

    try{

      sqlMap.startTransaction();

      indent=(Map)sqlMap.queryForObject("indent.getIndent",sellID);订货单主表记录

      indentList = sqlMap.queryForList("indent.getIndentList",sellID);订货单从表记录

      sqlMap.commitTransaction();

    }

    finally{

      sqlMap.endTransaction();

    }

 

l         动态条件查询

动态条件查询是指通过查询页面提交的动态条件来组合不同的sql语句

我们以前是通过

String sql =”select * from table where bh=’dd’”

If(request. getParameter(“par”)!=null&& request. getParameter(“par”). length()>0){

  sql += “ and field = ‘”+ request. getParameter(“par”)+”’”;

}

…….

这种方式来组合的

考虑到这个问题,ibatis引入了动态映射机制

在订货单查询就用到了这种动态条件查询,对应的类是com.indent.IndentQueryController

首先我通过

indentForm = (Map)bean.fillMap(mainField, request);方法将查询条件封装在Map

然后将这个查询条件的对象交给sqlMap查询

partCount = ((Integer) sqlMap.queryForObject("indent.getIndentQueryCount", indentForm)).intValue();获得了查询的记录数

indentList=sqlMap.queryForList("indent.getIndentQuery", indentForm, skipResult, PAGE_SIZE);获得了分页的记录集

sql映射是

<select id="getIndentQueryCount" parameterClass="java.util.Map" resultClass="java.lang.Integer">

  <![CDATA[

    select count(sellID) from os_sell

    where (depotCode = #depotCode#) and (oldSellID is null) and (status='1')

  ]]>

  <dynamic prepend="AND">

    <isNotEmpty prepend="AND" property="sellID">

      <![CDATA[(sellID like '%'+#sellID#+'%')]]>

    </isNotEmpty>

    <isNotEmpty prepend="AND" property="dealerName">

      <![CDATA[(dealerName like '%'+#dealerName#+'%')]]>

    </isNotEmpty>

    <isNotEmpty prepend="AND" property="orderCode">

      <![CDATA[(orderCode = #orderCode#)]]>

    </isNotEmpty>

    <isNotEmpty prepend="AND" property="orderDate1">

      <![CDATA[(orderDate >= #orderDate1#)]]>

    </isNotEmpty>

    <isNotEmpty prepend="AND" property="orderDate2">

      <![CDATA[(orderDate <= #orderDate2#)]]>

    </isNotEmpty>

  </dynamic>

</select>

 

 

<select id="getIndentQuery" parameterClass="java.util.Map" resultClass="java.util.HashMap">

  <![CDATA[

    select sellID, sellIDShow, dealerName, sumSellNum, sumFeeSell,

    orderName, orderDate, sourceExplain from V_OS_Sell

    where (depotCode = #depotCode#) and (oldSellID is null) and (status='1')

  ]]>

  <dynamic prepend="AND">

    <isNotEmpty prepend="AND" property="sellID">

      <![CDATA[(sellID like '%'+#sellID#+'%')]]>

    </isNotEmpty>

    <isNotEmpty prepend="AND" property="dealerName">

      <![CDATA[(dealerName like '%'+#dealerName#+'%')]]>

    </isNotEmpty>

    <isNotEmpty prepend="AND" property="orderCode">

      <![CDATA[(orderCode = #orderCode#)]]>

    </isNotEmpty>

    <isNotEmpty prepend="AND" property="orderDate1">

      <![CDATA[(orderDate >= #orderDate1#)]]>

    </isNotEmpty>

    <isNotEmpty prepend="AND" property="orderDate2">

      <![CDATA[(orderDate <= #orderDate2#)]]>

    </isNotEmpty>

  </dynamic>

  <![CDATA[

  order by orderDate desc, sellID desc

  ]]>

</select>

 

对于动态映射的配置,大家可以看<ibatis开发指南>31-34页里面讲得很清楚

 

l         操作语句

操作语句包括订货单的插,改,删

这里只说一下订货单的插入过程,类是com.indent.IndentAddSaveController

首先IndentAddSaveController在获得提交保存的请求后,将订货单主表信息封装在map,从表信息封装在list

    Map indent = (Map)bean.fillMap(mainField,request);

    List indentList = bean.fillMaps(childField,request);

然后通过事务管理,插入订货单主表信息,循环插入订货单子表信息

    try{

      sqlMap.startTransaction();

      sqlMap.insert("indent.insertIndent",indent);

      for (int i = 0; i < indentList.size(); i++) {

        indentPart = (Map)indentList.get(i) ;

        indentPart.put("sellID",sellID);

        sqlMap.insert("indent.insertIndentList",indentPart);

      }

      sqlMap.commitTransaction();

    }

    finally{

      sqlMap.endTransaction();

    }

对应的sql配置是

<insert id="insertIndent" parameterClass="java.util.Map">

   <![CDATA[

    insert into OS_Sell

    (sellID,dealerCode,dealerName,depotCode,orderCode,orderDate,

    sumSellNum,sumFeeSell,source,status,remark,isBack)

    values(#sellID#,#dealerCode#,#dealerName#,#depotCode#,#orderCode#,#orderDate#,

    #sumSellNum#,#sumFeeSell#,#source#,'1',#remark#,'2');

   ]]>

</insert>

 

<insert id="insertIndentList" parameterClass="java.util.Map">

   <![CDATA[

    insert into OS_SellList

    (sellID, partCode, partName, unit, priceSell, orderNum)

    values

    (#sellID#, #partCode#, #partName#, #unit#, #priceSell#, #orderNum#)

   ]]>

</insert>

 

l         调用存储过程

存储过程的调用在订货单新建过程中用到,订货单新建时首先要获得一个唯一的ID

对应的类是com.indent. IndentAddController

       首先我将存储过程需要用到的参数封装在map中,提交给sqlMap执行存储过程

       Map parMap = null;

    try {

      sqlMap.startTransaction();

      parMap = new HashMap();

      parMap.put("type","X");

      parMap.put("depot","A1118");

      parMap.put("code",null);

      sqlMap.update("common.getCode",parMap);

      sqlMap.commitTransaction();

    }

    finally {

      sqlMap.endTransaction();

    }

    String sellID=(String)parMap.get("code");

 

       SqlMap会根据common.getCode所定的parameterMap

<parameterMap id="getCodeParameters" class="java.util.Map" >

  <parameter property="type" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN" />

  <parameter property="depot" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>

  <parameter property="code" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT" nullValue=""/>

</parameterMap>

 

<procedure id="getCode" parameterMap="getCodeParameters">

  <![CDATA[

  {call ProcGetMaxId(?,?,?)}

  ]]>

</procedure>

的输入输出参数来定义存储过程中的参数

这里我将code这个字段定义为OUT型,那么存储过程执行后会将返回的唯一的ID号存储在code中,在程序中就通过

String sellID=(String)parMap.get("code");可以得到了。

 

l         注意一点

sqlMap的执行默认情况下是自动提交的,在没有用

try {

  sqlMap.startTransaction();

  ………..

  sqlMap.commitTransaction();

    finally {

      sqlMap.endTransaction();

    }

进行事务管理时

每执行一个更新,查询,等数据访问方法时都会打开,和关闭一次连接,

因此,在一个动作中多次调用sqlMap的数据访问方法时都应该用事务来管理,不管是查询,还是更新。

 

spring开发指南》中需要重点看的章节

l         Spring Bean封装机制 19-28页 要会配置Bean

l         Spring 高级特性 29-64页 要明白其中的登录例子的流程

 

ibatis开发指南》中需要重点看的章节

l         ibatis配置 11-16

l         SqlMapClient基本操作示例 16-17页 例1-6

l         OR 映射 19-25

l         动态映射 31-34

l         事务管理-基于JDBC的事务管理机制 35-36

 

 

附:

表结构

BS订货单主表

CREATE TABLE [dbo].[OS_Sell] (

       [SellID] [nvarchar] (17) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [DealerCode] [nvarchar] (6) COLLATE Chinese_PRC_CI_AS NULL ,

       [DealerName] [nvarchar] (60) COLLATE Chinese_PRC_CI_AS NULL ,

       [DepotCode] [nvarchar] (6) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [StockID] [nvarchar] (17) COLLATE Chinese_PRC_CI_AS NULL ,

       [OrderCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL ,

       [OrderDate] [datetime] NULL ,

       [SumSellNum] [numeric](9, 1) NULL ,

       [SumFeeSell] [numeric](10, 2) NULL ,

       [ChangeCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL ,

       [ChangeDate] [datetime] NULL ,

       [AuditCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL ,

       [AuditDate] [datetime] NULL ,

       [OutCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL ,

       [OutDate] [datetime] NULL ,

       [Source] [char] (1) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [Status] [char] (1) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [Remark] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,

       [IsBack] [char] (1) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [OldSellID] [nvarchar] (17) COLLATE Chinese_PRC_CI_AS NULL ,

       [BackStatus] [nvarchar] (1) COLLATE Chinese_PRC_CI_AS NULL ,

       [InvoiceCode] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL ,

       [InvoiceNO] [nvarchar] (10) COLLATE Chinese_PRC_CI_AS NULL ,

       [InvoiceDate] [datetime] NULL

) ON [PRIMARY]

 

BS订货单从表

CREATE TABLE [dbo].[OS_SellList] (

       [SellID] [nvarchar] (17) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [PartCode] [nvarchar] (30) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [PartName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,

       [Unit] [nvarchar] (4) COLLATE Chinese_PRC_CI_AS NULL ,

       [PriceSell] [numeric](8, 2) NULL ,

       [OrderNum] [numeric](9, 1) NULL ,

       [OutNum] [numeric](9, 1) NULL ,

       [BackNum] [numeric](9, 1) NULL

) ON [PRIMARY]

 

总部库存表

CREATE TABLE [dbo].[O_Storage] (

       [DepotCode] [nvarchar] (6) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [PartCode] [nvarchar] (30) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [PartName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,

       [Unit] [nvarchar] (4) COLLATE Chinese_PRC_CI_AS NULL ,

       [ProviderCode] [nvarchar] (4) COLLATE Chinese_PRC_CI_AS NULL ,

       [NumStorage] [numeric](9, 1) NULL ,

       [NumFreeze] [numeric](9, 1) NULL ,

       [PriceCost] [numeric](8, 2) NULL ,

       [PricePact] [numeric](8, 2) NULL ,

       [PriceMove] [numeric](8, 2) NULL ,

       [PriceStatus] [char] (1) COLLATE Chinese_PRC_CI_AS NOT NULL ,

       [StorageCode] [nvarchar] (14) COLLATE Chinese_PRC_CI_AS NULL

) ON [PRIMARY]

 

视图

--BS中的用户角色视图

--姜敏

CREATE       view v_BsUserRole

as

select

a.dealerCode,--经销商编号

a.areaCode,--区域编号

a.dealerName,--经销商名称

a.depotName,--仓库名称

a.kind,--等级分类

a.status as dealerStatus,--经销商状态

a.upDealerCode,--上级经销商代码

b.userCode,--用户代码

b.userName,--用户姓名

LOWER(b.password) as password ,--用户密码

b.lindType,--联系方式

b.status as userStatus,--用户状态

b.isAdmin,--是否管理员

c.roleCode,--角色编号

c.roleName--角色名称

 

from

p_dealer a

inner join p_user b on a.dealercode=b.depotcode

left outer join

  (select a.roleCode, a.roleName, b.userCode

   from r_bsRole a inner join r_bsRoleUser b on a.RoleCode = b.RoleCode) c

on b.userCode=c.userCode

 

 

订货单主表视图

CREATE  VIEW dbo.V_OS_Sell

AS

SELECT a.sellID, right(a.sellID,10) as sellIDShow, a.dealerCode, a.dealerName, f.areaCode, f.areaName, a.depotCode,

      h.dealerName AS depotName, a.stockID, a.orderCode, b.userName AS orderName,

      CONVERT(char(10), a.orderDate, 120) AS orderDate, cast(a.sumSellNum AS int)

      AS sumSellNum, a.sumFeeSell, a.changeCode, g.userName AS changeName,

      CONVERT(char(10), a.changeDate, 120) AS changeDate, a.auditCode,

      c.userName AS auditName, CONVERT(char(10), a.auditDate, 120) AS auditDate,

      a.outCode, d .userName AS outName, CONVERT(char(10), a.outDate, 120) AS outDate,

      a.source, (CASE a.source WHEN '1' THEN '转单' WHEN '2' THEN '自制' END)

      AS sourceExplain, a.status,

      (CASE a.status WHEN '1' THEN '已订货' WHEN '2' THEN '已转单' WHEN '3' THEN '已审核'

       WHEN '4' THEN '已出库' WHEN '5' THEN '已发运' WHEN ' 6 ' THEN '已确认' END)

      AS statusExplain, a.remark, a.isBack,

      (CASE a.isBack WHEN '1' THEN '' WHEN '2' THEN '' END) AS isBackExplain,

      a.oldSellID, a.backStatus,

      (CASE a.backStatus WHEN '1' THEN '未审核' WHEN '2' THEN '已审核' WHEN '3' THEN '已退货'

       END) AS backStatusExplain

FROM OS_Sell a INNER JOIN

      P_User b ON a.orderCode = b.userCode INNER JOIN

      P_Dealer e ON a.dealerCode = e.dealerCode INNER JOIN

      P_Dealer h ON a.depotCode = h.dealerCode LEFT OUTER JOIN

      P_Area f ON e.AreaCode = f.AreaCode LEFT OUTER JOIN

      P_User c ON a.auditCode = c.userCode LEFT OUTER JOIN

      P_User d ON a.outCode = d .userCode LEFT OUTER JOIN

      P_User g ON a.changeCode = g.userCode

 

 

订货单从表视图

/*

平台销售单子表

姜敏

*/

CREATE           view V_OS_SellList

as

 

select

a.sellID, --销售单ID

a.partCode, --零件号

a.partName, --零件名称

a.unit, --计量单位

a.priceSell, --销售价(合同成本价)

isnull((select top 1 pricePact from o_storage where depotCode='000001' and partCode = a.partCode),0) as factPrice,--当前的总部的销售价

cast(isnull((select top 1 numStorage from o_storage where depotCode = '000001' and partcode = a.partcode),0) as int) as numStorage,  --当前库存数量

cast(a.orderNum as int) as orderNum, --订货数量

a.priceSell*orderNum as orderSum, --订货金额

cast(a.outNum as int) as outNum, --出库数量

a.priceSell*outNum as outSum, --出库金额

cast(a.backNum as int) as backNum, --累计退票数量

a.priceSell*backNum as backSum, --累计退票金额

cast((a.orderNum+a.backNum) as int) as canBackNum, --可退数量

(a.orderNum+a.backNum)*a.priceSell as canBackSum--可退金额

 

from

OS_SellList a

inner join OS_Sell b on a.sellID = b.sellID

 

 

存储过程

--取单据号的存储过程--

CREATE    PROCEDURE ProcGetMaxId

@LX char(1),@CK nvarchar(6),@Code nvarchar(17) output

AS

Declare @i bigint,@No Varchar(11)

begin tran

Select @i=count(*) from P_MaxId where  (Code = @LX) and (DepotCode=@CK)

if @i>0

begin

  set @i=0

  Select @i=IDNO

  FROM P_MaxId

  WHERE (CONVERT(Varchar, CurrDate, 1) = CONVERT(Varchar, GETDATE(), 1))   AND

        (Code = @LX) and (DepotCode=@CK)

  if @i=0

  begin

     Set @No=Convert(Varchar,Getdate(),112)+'001'

     Update P_MaxId Set CurrDate=GetDate(),IDNO=Convert(bigint,@No) where  (Code = @LX) and (DepotCode=@CK)

  end

  else

  begin

    Update P_MaxId Set CurrDate=GetDate(),IDNO=IDNO+1 where  (Code = @LX) and (DepotCode=@CK)

  end

   Select @No=Convert(varchar,IDNO) from P_MaxId where (Code = @LX) and (DepotCode=@CK)

end

else

begin

     Set @No=Convert(Varchar,Getdate(),112)+'001'

     Insert P_MaxId(Code,DepotCode,CurrDate,IDNO) Values( @LX,@CK,GetDate(),Convert(bigint,@No) )

end

commit tran

set @Code= @CK+'_'+@LX+subString(@No,3,9)

--return 1

 

GO

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值