Mybatis系列之实战篇(中)

时间:2020-12-23 08:06:10

Mybatis系列之实战篇(中)

接着《Mybatis系列之实战篇(上)》,我们继续。

 

数据表实体类

Province类

package com.emerson.etao.entity.base.address;

/**
 * 省份实体类
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class Province {
	
	private int provinceId;
	
	private String provinceName;

	public int getProvinceId() {
		return provinceId;
	}

	public void setProvinceId(int provinceId) {
		this.provinceId = provinceId;
	}

	public String getProvinceName() {
		return provinceName;
	}

	public void setProvinceName(String provinceName) {
		this.provinceName = provinceName;
	}

	@Override
	public String toString() {
		return "Province [provinceId=" + provinceId + ", provinceName=" + provinceName + "]";
	}
}

City类

package com.emerson.etao.entity.base.address;

/**
 * 城市实体类
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class City {
	
	private int cityId;
	
	private String cityName;

	public int getCityId() {
		return cityId;
	}

	public void setCityId(int cityId) {
		this.cityId = cityId;
	}

	public String getCityName() {
		return cityName;
	}

	public void setCityName(String cityName) {
		this.cityName = cityName;
	}

	@Override
	public String toString() {
		return "City [cityId=" + cityId + ", cityName=" + cityName + "]";
	}

}

Area类

package com.emerson.etao.entity.base.address;

/**
 * 区域实体类
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class Area {
	
	private int areaId;
	
	private String areaName;

	public int getAreaId() {
		return areaId;
	}

	public void setAreaId(int areaId) {
		this.areaId = areaId;
	}

	public String getAreaName() {
		return areaName;
	}

	public void setAreaName(String areaName) {
		this.areaName = areaName;
	}

	@Override
	public String toString() {
		return "Area [areaId=" + areaId + ", areaName=" + areaName + "]";
	}
}

Purpose类

package com.emerson.etao.entity.base.address;

/**
 * 地址用途实体类
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class Purpose {
	
	public static final int PURPOSE_LEGAL = 1;
	public static final int PURPOSE_BILLTO = 2;
	public static final int PURPOSE_SHIPTO = 3;
	public static final int PURPOSE_DUNNING = 4;
	
	private int purposeId;
	
	private String purposeName;

	public int getPurposeId() {
		return purposeId;
	}

	public void setPurposeId(int purposeId) {
		this.purposeId = purposeId;
	}

	public String getPurposeName() {
		return purposeName;
	}

	public void setPurposeName(String purposeName) {
		this.purposeName = purposeName;
	}

	@Override
	public String toString() {
		return "Purpose [purposeId=" + purposeId + ", purposeName=" + purposeName + "]";
	}

}

Address类

package com.emerson.etao.entity.base.address;

import com.emerson.etao.entity.BaseEntity;

/**
 * 地址实体类
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class Address extends BaseEntity {
	
	private int addressId;
	
	private Province province;
	
	private City city;
	
	private Area area;
	
	private String street;
	
	private String zipCode;
	
	private String contactPerson;
	
	private String tel;
	
	private String fax;
	
	private String cellPhone;
	
	private String email;

	public int getAddressId() {
		return addressId;
	}

	public void setAddressId(int addressId) {
		this.addressId = addressId;
	}

	public Province getProvince() {
		return province;
	}

	public void setProvince(Province province) {
		this.province = province;
	}

	public City getCity() {
		return city;
	}

	public void setCity(City city) {
		this.city = city;
	}

	public Area getArea() {
		return area;
	}

	public void setArea(Area area) {
		this.area = area;
	}

	public String getStreet() {
		return street;
	}

	public void setStreet(String street) {
		this.street = street;
	}

	public String getZipCode() {
		return zipCode;
	}

	public void setZipCode(String zipCode) {
		this.zipCode = zipCode;
	}

	public String getContactPerson() {
		return contactPerson;
	}

	public void setContactPerson(String contactPerson) {
		this.contactPerson = contactPerson;
	}

	public String getTel() {
		return tel;
	}

	public void setTel(String tel) {
		this.tel = tel;
	}

	public String getFax() {
		return fax;
	}

	public void setFax(String fax) {
		this.fax = fax;
	}

	public String getCellPhone() {
		return cellPhone;
	}

	public void setCellPhone(String cellPhone) {
		this.cellPhone = cellPhone;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
	
	public String toDisplayString() {
		String result = province.getProvinceName() + ", " + city.getCityName() + ", " + area.getAreaName() + ", " +
	     this.street + ", " + this.zipCode + ", " + this.contactPerson;
		if ((this.tel != null) && !("".equals(this.tel))) {
			result += ", " + this.tel;
		}
		else if ((this.cellPhone != null) && !("".equals(this.cellPhone))) {
			result += ", " + this.cellPhone;
		}
		return result;
	}

	@Override
	public String toString() {
		return "Address [addressId=" + addressId + ", province=" + province + ", city=" + city + ", area=" + area
				+ ", street=" + street + ", zipCode=" + zipCode + ", contactPerson=" + contactPerson + ", tel=" + tel
				+ ", fax=" + fax + ", cellPhone=" + cellPhone + ", email=" + email + ", isValid=" + isValid
				+ ", createdTime=" + createdTime + ", updateTime=" + updateTime + "]";
	}
	

}

Party类

package com.emerson.etao.entity.base.customer;

import com.emerson.etao.entity.BaseEntity;

/**
 * 客户Party实体类
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class Party extends BaseEntity {
	
	private int partyId;

	private String partyName;

	private String country;

	private String area;

	public int getPartyId() {
		return partyId;
	}

	public void setPartyId(int partyId) {
		this.partyId = partyId;
	}

	public String getPartyName() {
		return partyName;
	}

	public void setPartyName(String partyName) {
		this.partyName = partyName;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getArea() {
		return area;
	}

	public void setArea(String area) {
		this.area = area;
	}

	@Override
	public String toString() {
		return "Party [partyId=" + partyId + ", partyName=" + partyName + ", country=" + country + ", area=" + area
				+ ", isValid=" + isValid + ", createdTime=" + createdTime + ", updateTime=" + updateTime + "]";
	}
}

Code类

package com.emerson.etao.entity.base.customer;

import com.emerson.etao.entity.BaseEntity;
import com.emerson.etao.entity.base.Plant;

/**
 * 客户代码实体类
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class Code extends BaseEntity {
	
	private int codeId;
	
	private String customerCode;
	
	private Party party;
	
	private Plant plant;
	
	public int getCodeId() {
		return codeId;
	}

	public void setCodeId(int codeId) {
		this.codeId = codeId;
	}

	public String getCustomerCode() {
		return customerCode;
	}

	public void setCustomerCode(String customerCode) {
		this.customerCode = customerCode;
	}

	public Plant getPlant() {
		return plant;
	}

	public void setPlant(Plant plant) {
		this.plant = plant;
	}

	public Party getParty() {
		return party;
	}

	public void setParty(Party party) {
		this.party = party;
	}

	@Override
	public String toString() {
		return "Code [codeId=" + codeId + ", customerCode=" + customerCode + ", party=" + party + ", plant=" + plant + ", isValid=" + isValid + ", createdTime=" + createdTime
				+ ", updateTime=" + updateTime + "]";
	}
}

Location类

package com.emerson.etao.entity.base.customer;

import com.emerson.etao.entity.BaseEntity;
import com.emerson.etao.entity.base.address.Address;
import com.emerson.etao.entity.base.address.Purpose;

/**
 * 客户位置实体类
 * 
 * 地址 + 用途,构成客户位置
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class Location extends BaseEntity {

	private int locationId;
	
	private int codeId;

	private Address address;

	private Purpose purpose;

	public int getLocationId() {
		return locationId;
	}

	public void setLocationId(int locationId) {
		this.locationId = locationId;
	}

	public int getCodeId() {
		return codeId;
	}

	public void setCodeId(int codeId) {
		this.codeId = codeId;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	public Purpose getPurpose() {
		return purpose;
	}

	public void setPurpose(Purpose purpose) {
		this.purpose = purpose;
	}
	
	public String toDisplayString() {
		return this.purpose.getPurposeName() + ": " + this.address.toDisplayString();
	}

	@Override
	public String toString() {
		return "Location [locationId=" + locationId + ", address=" + address + ", purpose=" + purpose + "]";
	}

}

以上这些都准备好了,下面可以开始着手写Mybatis映射文件了。我们自底向上,从地址开始写起。

 

Address类Dao接口、Service接口、映射文件及单元测试

Dao接口

Address作为基础类,不仅要实现基类(参见《Mybatis系列之实战篇(上)》中“Mybatisy接口及映射文件”)中约定的方法,还需要额外定义了三个方法,分别用于获取省、市、区的列表。

package com.emerson.etao.dao.base.address;

import java.util.List;

import com.emerson.etao.dao.IBaseDao;
import com.emerson.etao.entity.base.address.Address;
import com.emerson.etao.entity.base.address.Area;
import com.emerson.etao.entity.base.address.City;
import com.emerson.etao.entity.base.address.Province;

/**
 * 地址DAO接口
 * 
 * @author Chris Mao(Zibing)
 *
 */
public interface IAddressDao extends IBaseDao<Address> {
	
	/**
	 * 获取省份列表
	 * 
	 * @return
	 */
	public List<Province> getProvinceList();
	
	/**
	 * 获取指定省份的城市列表
	 * 
	 * @param provinceId
	 * @return
	 */
	public List<City> getCityList(int provinceId);
	
	/**
	 * 获取指定城市的地区列表
	 * 
	 * @param cityId
	 * @return
	 */
	public List<Area> getAreaList(int cityId);

}

映射文件

由于我们使用了接口式编程,所以映射文件中的名称空间名称必须和我们定义的接口全限定名一致! 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.emerson.etao.dao.base.address.IAddressDao">
	<sql id="selectColumns">
		address_id, province_id, province_name, city_id, city_name,
		area_id, street, zip_code, contact_person, tel, fax, cell_phone,
		email, is_valid, created_time, update_time
	</sql>

	<sql id="insertColumns">
		province_id, city_id, area_id, street, zip_code,
		contact_person, tel, fax, cell_phone, email, is_valid,
		created_time
	</sql>

	<!-- 省份映射关系 -->
	<resultMap id="provinceResultMap" type="com.emerson.etao.entity.base.address.Province">
		<id property="provinceId" column="province_id" />
		<result property="provinceName" column="province_name" />
	</resultMap>

	<!-- 城市映射关系 -->
    <resultMap id="cityResultMap" type="com.emerson.etao.entity.base.address.City">
		<id property="cityId" column="city_id" />
		<result property="cityName" column="city_name" />
	</resultMap>

	<!-- 地区映射关系 -->
    <resultMap id="areaResultMap" type="com.emerson.etao.entity.base.address.Area">
		<id property="areaId" column="area_id" />
		<result property="areaName" column="area_name" />
	</resultMap>

	<!-- 地址映射关系 -->
    <resultMap id="addressResultMap" type="com.emerson.etao.entity.base.address.Address">
		<id property="addressId" column="address_id" />
		<result property="street" column="street" />
		<result property="zipCode" column="zip_code" />
		<result property="contactPerson" column="contact_person" />
		<result property="fax" column="fax" />
		<result property="tel" column="tel" />
		<result property="cellPhone" column="cell_phone" />
		<result property="email" column="email" />
		<result property="isValid" column="is_valid" />
		<result property="createdTime" column="created_time" />
		<result property="updateTime" column="update_time" />
		<association property="province" column="province_id"
			resultMap="provinceResultMap" />
		<association property="city" column="city_id" resultMap="cityResultMap" />
		<association property="area" column="area_id" resultMap="areaResultMap" />
	</resultMap>

	<!-- 地址用途映射关系 -->
    <resultMap id="purposeResultMap" type="com.emerson.etao.entity.base.address.Purpose">
		<id property="purposeId" column="purpose_id" />
		<result property="purposeName" column="purpose_name" />
	</resultMap>

	<!-- 按Id值查询地址 -->
    <select id="getById" parameterType="int" resultMap="addressResultMap">
		SELECT
		<include refid="selectColumns"></include>
		FROM vw_address WHERE address_id = #{id}
	</select>

	<!-- 获取所有地址 -->
    <select id="getAll" resultMap="addressResultMap">
		SELECT
		<include refid="selectColumns"></include>
		FROM vw_address ORDER BY province_id, city_id, area_id
	</select>

	<!-- 查询省份列表 -->
	<select id="getProvinceList" resultType="com.emerson.etao.entity.base.address.Province">
		SELECT province_id,
		province_name, is_valid, created_time, update_time FROM
		addr_province
		ORDER BY province_name
	</select>

	<!-- 查询指定省份下的城市列表 -->
	<select id="getCityList" parameterType="int"
		resultType="com.emerson.etao.entity.base.address.City">
		SELECT city_id, city_name, is_valid, created_time,
		update_time FROM
		addr_city WHERE province_id = #{id} ORDER BY city_name
	</select>

	<!-- 查询指定城市下的地区列表 -->
	<select id="getAreaList" parameterType="int"
		resultType="com.emerson.etao.entity.base.address.Area">
		SELECT area_id, area_name, is_valid, created_time,
		update_time FROM
		addr_area WHERE city_id = #{id} ORDER BY area_name
	</select>

	<!-- 
	  查询符合查询条年的地址,可以按
	  address_id, province_id, province_name, city_id, city_name, area_id, 
	  area_name, street, zip_code, contact_person, tel, fax, cell_phone, email
	  进行查询
	 -->
    <select id="find" parameterType="com.emerson.etao.entity.base.address.Address"
		resultMap="addressResultMap">
		SELECT
		<include refid="selectColumns"></include>
		FROM vw_address
		<where>
			<if test="addressId != 0">AND address_id = #{addressId}</if>
			<if test="province != null and province.provinceId != 0">AND province_id = #{province.provinceId}</if>
			<if test="province != null and province.provinceName != null">AND province_name LIKE CONCAT('%',
				#{province.provinceName}, '%')</if>
			<if test="city != null and city.cityId != 0">AND city_id = #{city.cityId}</if>
			<if test="city != null and city.cityName != null">AND city_name LIKE CONCAT('%', #{city.cityName}, '%')
			</if>
			<if test="area != null and area.areaId != 0">AND area_id = #{area.areaId}</if>
			<if test="area != null and area.areaName != null">AND area_name LIKE CONCAT('%', #{area.areaName}, '%')
			</if>
			<if test="street != null">AND street LIKE CONCAT('%', #{street}, '%')</if>
			<if test="zipCode != null">AND zip_code LIKE CONCAT('%', #{zipCode}, '%')</if>
			<if test="contactPerson != null">AND contact_person LIKE CONCAT('%', #{contactPerson},
				'%')</if>
			<if test="tel != null">AND tel LIKE CONCAT('%', #{tel}, '%')</if>
			<if test="fax != null">AND fax LIKE CONCAT('%', #{fax}, '%')</if>
			<if test="cellPhone != null">AND cell_phone LIKE CONCAT('%', #{cellPhone}, '%')</if>
			<if test="email != null">AND email LIKE CONCAT('%', #{email}, '%')</if>
		</where>
		ORDER BY province_id, city_id, area_id
	</select>

	<!-- 插入数据并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
	<insert id="insert" parameterType="com.emerson.etao.entity.base.address.Address"
		useGeneratedKeys="true" keyProperty="addressId">
		INSERT INTO address(
		<include refid="insertColumns"></include>
		)
		VALUES(#{province.provinceId}, #{city.cityId}, #{area.areaId},
		#{street}, #{zipCode}, #{contactPerson}, #{tel}, #{fax},
		#{cellPhone},
		#{email}, #{isValid}, #{createdTime})
	</insert>

	<!-- 批量新增 -->
	<insert id="batchInsert" parameterType="java.util.List">
		INSERT INTO address(
		<include refid="insertColumns"></include>
		) VALUES
		<foreach collection="list" item="addr" separator=",">
			(#{addr.province.provinceId}, #{addr.city.cityId},
			#{addr.area.areaId}, #{addr.street}, #{addr.zip_code},
			#{addr.contactPerson}, #{addr.tel}, #{addr.fax}, #{addr.cellPhone},
			#{addr.email}, #{addr.isValid}, #{addr.createdTime})
		</foreach>
	</insert>

	<!-- 更新数据 -->
	<update id="update" parameterType="com.emerson.etao.entity.base.address.Address">
		UPDATE address
		<set>
			<if test="province != null and province.provinceId != 0">province_id = #{province.provinceId},</if>
			<if test="city != null and city.cityId != 0">city_id = #{city.cityId},</if>
			<if test="area != null and area.areaId != 0">area_id = #{area.areaId},</if>
			<if test="street != null">street = #{street},</if>
			<if test="zipCode != null">zip_code = #{zipCode},</if>
			<if test="contactPerson != null">contact_person = #{contactPerson},</if>
			<if test="tel != null">tel = #{tel},</if>
			<if test="fax != null">fax = #{fax},</if>
			<if test="cellPhone != null">cell_phone = #{cellPhone},</if>
			<if test="email != null">email = #{email}</if>
		</set>
		WHERE address_id = #{addressId}
	</update>

	<!-- 根据传入的Id值,删除单条记录 -->
	<delete id="delete" parameterType="int">
		UPDATE address SET is_valid =
		0 WHERE address_id = #{id}
	</delete>

	<!-- 根据传入的Id值列表,删除多条记录 -->
	<delete id="batchDelete" parameterType="java.util.List">
		UPDATE address SET is_valid = 0 WHERE address_id in
		<foreach collection="list" item="item" index="index" open="("
			close=")" separator=",">
			#{item}
		</foreach>
	</delete>
</mapper>
这里着重讲解一下id为find的select元素的写法。这是一个查询方法,把查询条件封装成一个实体类对象,然后根据其属性值,动态生成SQL查询语句。Address对象中又嵌套有Province / City / Arae三个子对象,所以要创建查询语句时, 在引用其属性值之前,一定要判断其是否为null值,否则有可能会得到空引用的错误
	<!-- 
	  查询符合查询条年的地址,可以按
	  address_id, province_id, province_name, city_id, city_name, area_id, 
	  area_name, street, zip_code, contact_person, tel, fax, cell_phone, email
	  进行查询
	 -->
    <select id="find" parameterType="com.emerson.etao.entity.base.address.Address"
		resultMap="addressResultMap">
		SELECT
		<include refid="selectColumns"></include>
		FROM vw_address
		<where>
			<if test="addressId != 0">AND address_id = #{addressId}</if>
			<if test="province != null and province.provinceId != 0">AND province_id = #{province.provinceId}</if>
			<if test="province != null and province.provinceName != null">AND province_name LIKE CONCAT('%',
				#{province.provinceName}, '%')</if>
			<if test="city != null and city.cityId != 0">AND city_id = #{city.cityId}</if>
			<if test="city != null and city.cityName != null">AND city_name LIKE CONCAT('%', #{city.cityName}, '%')
			</if>
			<if test="area != null and area.areaId != 0">AND area_id = #{area.areaId}</if>
			<if test="area != null and area.areaName != null">AND area_name LIKE CONCAT('%', #{area.areaName}, '%')
			</if>
			<if test="street != null">AND street LIKE CONCAT('%', #{street}, '%')</if>
			<if test="zipCode != null">AND zip_code LIKE CONCAT('%', #{zipCode}, '%')</if>
			<if test="contactPerson != null">AND contact_person LIKE CONCAT('%', #{contactPerson},
				'%')</if>
			<if test="tel != null">AND tel LIKE CONCAT('%', #{tel}, '%')</if>
			<if test="fax != null">AND fax LIKE CONCAT('%', #{fax}, '%')</if>
			<if test="cellPhone != null">AND cell_phone LIKE CONCAT('%', #{cellPhone}, '%')</if>
			<if test="email != null">AND email LIKE CONCAT('%', #{email}, '%')</if>
		</where>
		ORDER BY province_id, city_id, area_id
	</select>

在映射文件中除了用到了select / insert / update / delete 元素,还使用到了创建动态SQL的where / set / if元素,以及foreach,小伙伴可以慢慢体会这些元素的使用方法。

 

Service接口及实现

接口定义。

package com.emerson.etao.service.base.address;

import java.util.List;

import com.emerson.etao.entity.base.address.Address;
import com.emerson.etao.entity.base.address.Area;
import com.emerson.etao.entity.base.address.City;
import com.emerson.etao.entity.base.address.Province;
import com.emerson.etao.service.IBaseService;

/**
 * 客户地址服务层接口
 * 
 * @author Chris Mao(Zibing)
 *
 */
public interface IAddressService extends IBaseService<Address> {
	
	/**
	 * 获取省份列表
	 * 
	 * @return
	 */
	public List<Province> getProvinceList();
	
	/**
	 * 获取指定省份的城市列表
	 * 
	 * @param provinceId
	 * @return
	 */
	public List<City> getCityList(int provinceId);
	
	/**
	 * 获取指定城市的地区列表
	 * 
	 * @param cityId
	 * @return
	 */
	public List<Area> getAreaList(int cityId);

}

接口实现,这里需要在接口实现类的定义处使用Service注解将其定义为一个J2EE组件。

package com.emerson.etao.service.impl.base.address;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.emerson.etao.dao.IBaseDao;
import com.emerson.etao.dao.base.address.IAddressDao;
import com.emerson.etao.entity.base.address.Address;
import com.emerson.etao.entity.base.address.Area;
import com.emerson.etao.entity.base.address.City;
import com.emerson.etao.entity.base.address.Province;
import com.emerson.etao.service.base.address.IAddressService;
import com.emerson.etao.service.impl.BaseServiceImpl;

/**
 * 地址服务接口
 * 
 * @author Chris Mao(Zibing)
 *
 */
@Service("addressService")
public class AddressServiceImpl extends BaseServiceImpl<Address> implements IAddressService {

	@Resource
	private IAddressDao dao;

	@Override
	protected IBaseDao<Address> getBaseDao() {
		return this.dao;
	}
	
	@Override
	public List<Province> getProvinceList() {
		return this.dao.getProvinceList();
	}
	
	@Override
	public List<City> getCityList(int provinceId) {
		return this.dao.getCityList(provinceId);
	}
	
	@Override
	public List<Area> getAreaList(int cityId) {
		return this.dao.getAreaList(cityId);
	}

}

单元测试

这些都写好之后,就可以对我们写的代码进行单元测试了。我们一定要培养自己有写单元测试的习惯,这样不仅可以确保自己的代码质量,即便在将来我们对代码进行重构或是增加功能时,这些测试代码仍可以复用,确保我们不会因为重构或是增加新的功能引入新的错误。通过了单元测试并不能说明我们的程序完全没有作何问题。单元测试只能确保我们的程序代码没有技术错误,无法保证没有业务错误。所以后继我们还会对程序进行功能测试,来暴露出程序上的功能错误。

package com.emerson.etao.service.address;

import static org.junit.Assert.*;

import java.util.List;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.emerson.etao.entity.base.address.*;
import com.emerson.etao.service.base.address.IAddressService;

/**
 * 地址服务测试类
 * 
 * @author Chris Mao(Zibing)
 *
 */
public class AddressServiceTest {

	private static IAddressService addressService;
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		ApplicationContext ac = new ClassPathXmlApplicationContext("root-context-test.xml");
		addressService = (IAddressService) ac.getBean("addressService");
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		addressService = null;
	}

	@Test
	public void testGetById() {
		System.out.println("testGetById start...");
		Address address = addressService.getById(1);
		assertNotNull(address);
		System.out.println("testGetById end...");
	}

	@Test
	public void testGetAll() {
		System.out.println("testGetAll start...");
		List<Address> list = addressService.getAll(0);
		assertNotNull(list);
		System.out.println("testGetAll end...");
	}
	
	@Test
	public void testFind() {
		System.out.println("testFind start...");
		Address address = new Address();
		address.setZipCode("433");
		List<Address> list = addressService.find(address);
		assertEquals(1, list.size());
		
		address.setZipCode(null);
		address.setProvince(new Province());
		address.getProvince().setProvinceName("上海");
		list = addressService.find(address);
		assertEquals(1, list.size());
		System.out.println("testFind end...");
	}

	@Test
	public void testInsert() {
		System.out.println("testInsert start...");
		Address address = new Address();
		Province province = new Province();
		City city = new City();
		Area area = new Area();
		province.setProvinceId(2);
		city.setCityId(2);
		area.setAreaId(26);
		address.setProvince(province);
		address.setCity(city);
		address.setArea(area);
		address.setStreet("工艺品公司进出口仓库8号库军工路1300");
		address.setZipCode("200433");
		address.setContactPerson("陈伟民");
		address.setTel("021-65797887");
		address.setFax(null);
		address.setCellPhone(null);
		addressService.insert(address);
		System.out.println("testInsert end...");
	}
	
	@Test
	public void testBatchInsert() {
		System.out.println("testBatchInsert start...");
		System.out.println("testBatchInsert end...");
	}

	@Test
	public void testUpdate() {
		System.out.println("testUpdate start...");
		Address address = addressService.getById(1);
		address.setEmail("chris.mao.zb@163.com");
		int effectedRows = addressService.update(address);
		assertEquals(1, effectedRows);
		System.out.println("testUpdate end...");
	}

	@Test
	public void testDelete() {
		System.out.println("testDelete start...");
		int effectedRows = addressService.delete(1);
		assertEquals(1, effectedRows);
		System.out.println("testDelete end...");
	}
	
	@Test
	public void testBatchDelete() {
		System.out.println("testBatchDelete start...");
		System.out.println("testBatchDelete end...");
	}

	@Test
	public void testGetProvinceList() {
		System.out.println("testGetProvinceList start...");
		List<Province> list = addressService.getProvinceList();
		assertEquals(34, list.size());
		System.out.println("testGetProvinceList end...");
	}

	@Test
	public void testGetCityList() {
		System.out.println("testGetCityList start...");
		List<City> list = addressService.getCityList(12); // Jiangsu
		assertEquals(13, list.size());
		System.out.println("testGetCityList end...");
	}

	@Test
	public void testGetAreaList() {
		System.out.println("testGetAreaList start...");
		List<Area> list = addressService.getAreaList(113); // Suzhou
		assertEquals(13, list.size());
		System.out.println("testGetAreaList end...");
	}
}

 

Plant / Party / Code其实现步骤和Address类一样,也是要经过定义Dao接口、编写映射文件、定义服务层接口并实现其功能,以及单元测试这样四步。本文重点放在了映射文件的编写上,所以,这里就仅贴出其他类的映射文件内容,有兴趣的小伙伴也可以试着自己完成接口部分和测试部分的编写。

 

Plant映射文件

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.emerson.etao.dao.base.IPlantDao">
    <sql id="selectColumns">
        plant_id, plant_code, plant_name, is_valid, created_time, update_time
    </sql>

    <sql id="insertColumns">
        plant_code, plant_name, is_valid, created_time
    </sql>

    <select id="getById" parameterType="int" resultType="com.emerson.etao.entity.base.Plant">
        SELECT
        <include refid="selectColumns"></include>
        FROM plant WHERE plant_id = #{id}
    </select>

    <select id="getAll" resultType="com.emerson.etao.entity.base.Plant">
        SELECT
        <include refid="selectColumns"></include>
        FROM plant ORDER BY plant_id
    </select>

    <!-- 插入数据并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
    <insert id="insert" parameterType="com.emerson.etao.entity.base.Plant" useGeneratedKeys="true" keyProperty="plantId">
        INSERT INTO plant(<include refid="insertColumns"></include>)
        VALUES(#{plantCode}, #{plantName}, #{isValid}, #{createdTime})
    </insert>

    <!-- 批量新增 -->
    <insert id="batchInsert" parameterType="java.util.List">
        INSERT INTO plant(<include refid="insertColumns"></include>) VALUES
        <foreach collection="list" item="p" separator=",">
            (#{p.plantCode}, #{p.plantName}, #{p.isValid}, #{p.createdTime})
        </foreach>
    </insert>

    <!-- 更新数据 -->
    <update id="update" parameterType="com.emerson.etao.entity.base.Plant">
        UPDATE plant
        <set>
        </set>
        WHERE plant_id = #{plantId}
    </update>

    <!-- 根据传入的Id值,删除单条记录 -->
    <delete id="delete" parameterType="int">
        UPDATE plant SET is_valid = 0 WHERE plant_id = #{id}
    </delete>

    <!-- 根据传入的Id值列表,删除多条记录 -->
    <delete id="batchDelete" parameterType="java.util.List">
        UPDATE plant SET is_valid = 0 WHERE plant_id in
        <foreach collection="list" item="item" index="index" open="("
            close=")" separator=",">
            #{item}
        </foreach>
    </delete>
</mapper>

Party映射文件

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.emerson.etao.dao.base.customer.IPartyDao">
	<sql id="selectColumns">
		party_id, party_name, country, area, is_valid,
		created_time, update_time
	</sql>

	<sql id="insertColumns">
		party_name, country, area, is_valid, created_time
	</sql>

	<select id="getById" parameterType="int"
		resultType="com.emerson.etao.entity.base.customer.Party">
		SELECT
		<include refid="selectColumns"></include>
		FROM customer_party WHERE party_id = #{id}
	</select>

	<select id="getAll" resultType="com.emerson.etao.entity.base.customer.Party">
		SELECT
		<include refid="selectColumns"></include>
		FROM customer_party ORDER BY party_id
	</select>

	<select id="find" parameterType="com.emerson.etao.entity.base.customer.Party"
		resultType="com.emerson.etao.entity.base.customer.Party">
		SELECT
		<include refid="selectColumns"></include>
		FROM customer_party
		<where>
			<if test="partyName != null">party_name LIKE CONCAT('%', #{partyName}, '%')</if>
			<if test="country != null">OR country LIKE CONCAT('%', #{country}, '%')</if>
			<if test="area != null">OR area LIKE CONCAT('%', #{area}, '%')</if>
			<if test="isValid != null">AND is_valid = #{isValid}</if>
		</where>
	</select>

	<select id="getAllCode" parameterType="int"
		resultMap="com.emerson.etao.dao.base.customer.ICodeDao.codeResultMap">
	    SELECT <include refid="com.emerson.etao.dao.base.customer.ICodeDao.selectColumns"></include>
	    FROM vw_customer_code WHERE party_id = #{id}
        ORDER BY party_id, customer_code
	</select>

	<!-- 插入数据并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
	<insert id="insert" parameterType="com.emerson.etao.entity.base.customer.Party"
		useGeneratedKeys="true" keyProperty="partyId">
		INSERT INTO customer_party(
		<include refid="insertColumns"></include>
		)
		VALUES(#{partyName}, #{country}, #{area}, #{isValid}, #{createdTime})
	</insert>

	<!-- 批量新增 -->
	<insert id="batchInsert" parameterType="java.util.List">
		INSERT INTO customer_party(
		<include refid="insertColumns"></include>
		) VALUES
		<foreach collection="list" item="party" separator=",">
			(#{party.partyName}, #{party.country}, #{party.area},
			#{party.isValid}, #{party.createdTime})
		</foreach>
	</insert>

	<!-- 更新数据 -->
	<update id="update" parameterType="com.emerson.etao.entity.base.customer.Party">
		UPDATE customer_party
		<set>
			<if test="partyName != null">party_name = #{partyName},</if>
			<if test="country != null">country = #{country},</if>
			<if test="area != null">area = #{area},</if>
			<if test="isValid != null">is_valid = #{isValid},</if>
		</set>
		WHERE party_id = #{partyId}
	</update>

	<!-- 根据传入的Id值,删除单条记录 -->
	<delete id="delete" parameterType="int">
		UPDATE customer_party SET
		is_valid = 0
		WHERE party_id = #{id}
	</delete>

	<!-- 根据传入的Id值列表,删除多条记录 -->
	<delete id="batchDelete" parameterType="java.util.List">
		UPDATE customer_party SET is_valid = 0 WHERE party_id in
		<foreach collection="list" item="item" index="index" open="("
			close=")" separator=",">
			#{item}
		</foreach>
	</delete>
</mapper>

Code映射文件

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.emerson.etao.dao.base.customer.ICodeDao">
	<sql id="selectColumns">
		code_id ,customer_code, plant_id, party_id,
		is_valid, created_time, update_time,
		plant_code, plant_name,
		plant_is_valid, plant_created_time,
		plant_update_time,
		party_name, country, area, party_is_valid,
		party_created_time, party_update_time
	</sql>

	<sql id="insertColumns">
		customer_code, plant_id, party_id, is_valid, created_time
	</sql>

	<!-- 工厂映射关系 -->
    <resultMap id="plantResultMap" type="com.emerson.etao.entity.base.Plant">
		<id property="plantId" column="plant_id" />
		<result property="plantCode" column="plant_code" />
		<result property="plantName" column="plant_name" />
		<result property="isValid" column="plant_is_valid" />
		<result property="createdTime" column="plant_created_time" />
		<result property="updateTime" column="plant_update_time" />
	</resultMap>

	<!-- 客户Party映射关系 -->
    <resultMap id="partyResultMap" type="com.emerson.etao.entity.base.customer.Party">
		<id property="partyId" column="party_id" />
		<result property="partyName" column="party_name" />
		<result property="country" column="country" />
		<result property="area" column="area" />
		<result property="isValid" column="party_is_valid" />
		<result property="createdTime" column="party_created_time" />
		<result property="updateTime" column="party_update_time" />
	</resultMap>

	<!-- 客户代码映射关系 -->
    <resultMap id="codeResultMap" type="com.emerson.etao.entity.base.customer.Code">
		<id property="codeId" column="code_id" />
		<result property="customerCode" column="customer_code" />
		<result property="isValid" column="is_valid" />
		<result property="createdTime" column="created_time" />
		<result property="updateTime" column="update_time" />
		<association property="party" column="party_id" resultMap="partyResultMap"></association>
		<association property="plant" column="plant_id" resultMap="plantResultMap"></association>
	</resultMap>

	<!-- 客户地点映射关系,包含地址和用途 -->
    <resultMap id="locationResultMap"
		type="com.emerson.etao.entity.base.customer.Location">
		<id property="locationId" column="location_id" />
		<result property="codeId" column="code_id" />
		<result property="isValid" column="is_valid" />
		<result property="createdTime" column="created_time" />
		<result property="updateTime" column="update_time" />
		<association property="address" column="address_id"
			resultMap="com.emerson.etao.dao.base.address.IAddressDao.addressResultMap" />
		<association property="purpose" column="purpose_id"
			resultMap="com.emerson.etao.dao.base.address.IAddressDao.purposeResultMap" />
	</resultMap>

	<!-- 按Id值查询客户代码 -->
    <select id="getById" parameterType="int" resultMap="codeResultMap">
		SELECT
		<include refid="selectColumns"></include>
		FROM vw_customer_code WHERE code_id = #{id}
	</select>

	<!-- 获取所有客户代码 -->
    <select id="getAll" resultMap="codeResultMap">
		SELECT
		<include refid="selectColumns"></include>
		FROM vw_customer_code ORDER BY customer_code
	</select>

	<!-- 
	  查询符合条件的客户代码,可以按
	  customer_code, plant_id, plant_code, party_id, party_name,
	  deliverty_type_id, shippint_term_id, payment_term_id, rebate_allowed,
	  credit_allowed, sp_allowed
	  进行查询
	 -->
    <select id="find" parameterType="com.emerson.etao.entity.base.customer.Code"
		resultMap="codeResultMap">
		SELECT
		<include refid="selectColumns"></include>
		FROM vw_customer_code
		<where>
			<if test="customerCode != null">customer_code LIKE CONCAT('%', #{customerCode}, '%')</if>
			<if test="plant != null and plant.plantId != 0">AND plant_id = #{plant.plantId}</if>
			<if test="plant != null and plant.plantCode != null">AND plant_code LIKE CONCAT('%', #{plant.plantCode}, '%')
			</if>
			<if test="party != null and party.partyId != 0">AND party_id = #{party.partyId}</if>
			<if test="party != null and party.partyName != null">AND party_name LIKE CONCAT('%', #{party.partyName}, '%')
			</if>
		</where>
		ORDER BY customer_code
	</select>

	<!-- 
	  查询符合条件的所有地点记录,可以按
	  location_id, code_id, purpose_id, purpose_name
	  进行查询
	-->
	<select id="findLocation" parameterType="com.emerson.etao.entity.base.customer.Location"
		resultMap="locationResultMap">
		SELECT location_id, address_id, code_id, purpose_id, purpose_name,
        province_id, province_name, city_id, city_name, area_id, area_name,
        street, zip_code, contact_person, tel, fax, cell_phone, email,
        is_valid, created_time, update_time
        FROM vw_customer_location
        <where>
            <if test="locationId != 0">AND location_id = #{locationId}</if>
            <if test="codeId != 0">AND code_id = #{codeId}</if>
            <if test="purpose != null and purpose.purposeId != 0">AND purpose_id = #{purpose.purposeId}</if>
            <if test="purpose != null and purpose.purposeName != null">AND purpose_name LIKE CONCAT('%', #{purpose.purposeName}, '%')</if>
        </where>
	</select>

	<!-- 插入数据并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
	<insert id="insert" parameterType="com.emerson.etao.entity.base.customer.Code"
		useGeneratedKeys="true" keyProperty="codeId">
		INSERT INTO customer_code(
		<include refid="insertColumns"></include>
		)
		VALUES(#{customerCode}, #{plant.plantId}, #{party.partyId},
		#{isValid}, #{createdTime})
	</insert>

	<!-- 批量新增 -->
	<insert id="batchInsert" parameterType="java.util.List">
		INSERT INTO customer_code(
		<include refid="insertColumns"></include>
		) VALUES
		<foreach collection="list" item="c" separator=",">
			(#{c.customerCode}, #{c.plant.plantId}, #{c.party.partyId},
			#{c.isValid}, #{c.createdTime})
		</foreach>
	</insert>

	<!-- 
	  创建客户地点
	  需要先创建或是选取一个地址,再选择一个用途,并与客户代码进行绑定
	-->
    <insert id="createLocation" parameterType="com.emerson.etao.entity.base.customer.Location"
		useGeneratedKeys="true" keyProperty="locationId">
		INSERT INTO customer_location
		(code_id, address_id, purpose_id, is_valid, created_time)
		VALUES(#{codeId}, #{address.addressId}, #{purpose.purposeId},
		#{isValid}, #{createdTime})
	</insert>

	<!-- 更新数据 -->
	<update id="update" parameterType="com.emerson.etao.entity.base.customer.Code">
		UPDATE customer_code
		<set>
			<if test="plant != null and plant.plantId != 0">plant_id = #{plant.plantId},</if>
			<if test="party != null and party.partyId != 0">party_id = #{party.partyId},</if>
		</set>
		WHERE code_id = #{codeId}
	</update>

	<!-- 根据传入的Id值,删除单条记录 -->
	<delete id="delete" parameterType="int">
		UPDATE customer_code SET
		is_valid = 0 WHERE code_id = #{id}
	</delete>

	<!-- 根据传入的Id值列表,删除多条记录 -->
	<delete id="batchDelete" parameterType="java.util.List">
		UPDATE customer_code SET is_valid = 0 WHERE id in
		<foreach collection="list" item="item" index="index" open="("
			close=")" separator=",">
			#{item}
		</foreach>
	</delete>

	<!-- 删除客户地点 -->
    <delete id="removeLocation" parameterType="int">
		DELETE FROM customer_location WHERE location_id = #{id}
	</delete>
</mapper>

至此,这个示例的代码部分已全部讲解完毕。在《Mybatis系列这实战篇(下)》中,我会对开发中需要注意的问题点进行总结。


附录

Mybatis系列(一)入门

Mybatis系列(二)配置

Mybatis系列(三)简单示例

Mybatis系列(四)映射文件

Mybatis系列(五)动态SQL

Mybatis系列(六)接口式编程

Mybatis系列(七)关联映射

Mybatis系列(八)集合映射

Mybatis系列(九)Spring & Mybatis整合