复习电商笔记-8

 

整合通用Mapper到项目中

 

 

第一步:在jt-parent项目的pom.xml文件中依赖jar包

<!-- 通用Mapper -->
<dependency>
	<groupId>com.github.abel533</groupId>
	<artifactId>mapper</artifactId>
	<version>2.3.2</version>
</dependency>

 

 

第二步:加入Mapper

在下面的接口中扩展了批量删除功能,这是官方没有提供的。

SysMapper接口代码如下:

package com.jt.manage.mapper.base.mapper;

import java.util.List;

import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;

public interface SysMapper<T> {

    /**
     * 根据主键ID批量删除
     * 
     * @param key
     * @return
     */
    @DeleteProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    int deleteByIDS(@Param("ids") Object[] key);

    /**
     * 根据实体类不为null的字段进行查询,条件全部使用=号and条件
 * 
     * @param record
     * @return
     */
    @SelectProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    List<T> select(T record);

    /**
     * 根据实体类不为null的字段查询总数,条件全部使用=号and条件
     * 
     * @param record
     * @return
     */
    @SelectProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    int selectCount(T record);

    /**
     * 根据主键进行查询,必须保证结果唯一 单个字段做主键时,可以直接写主键的值 联合主键时,key可以是实体类,也可以是Map
     * 
     * @param key
     * @return
     */
    @SelectProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    T selectByPrimaryKey(Object key);

    /**
     * 插入一条数据 支持Oracle序列,UUID,类似Mysql的INDENTITY自动增长(自动回写) 优先使用传入的参数值,参数值空时,才会使用序列、UUID,自动增长
     * 
     * @param record
     * @return
     */
    @InsertProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    int insert(T record);

    /**
     * 插入一条数据,只插入不为null的字段,不会影响有默认值的字段 支持Oracle序列,UUID,类似Mysql的INDENTITY自动增长(自动回写)
     * 优先使用传入的参数值,参数值空时,才会使用序列、UUID,自动增长
     * 
     * @param record
     * @return
     */
    @InsertProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    int insertSelective(T record);

    /**
* 根据实体类中字段不为null的条件进行删除,条件全部使用=号and条件
     * 
     * @param key
     * @return
     */
    @DeleteProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    int delete(T key);

    /**
     * 通过主键进行删除,这里最多只会删除一条数据 单个字段做主键时,可以直接写主键的值 联合主键时,key可以是实体类,也可以是Map
     * 
     * @param key
     * @return
     */
    @DeleteProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    int deleteByPrimaryKey(Object key);

    /**
     * 根据主键进行更新,这里最多只会更新一条数据 参数为实体类
     * 
     * @param record
     * @return
     */
    @UpdateProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    int updateByPrimaryKey(T record);

    /**
     * 根据主键进行更新 只会更新不是null的数据
     * 
     * @param record
     * @return
     */
    @UpdateProvider(type = SysMapperProvider.class, method = "dynamicSQL")
    int updateByPrimaryKeySelective(T record);

}

SysMapperProvider.java拦截器代码如下:

package com.jt.manage.mapper.base.mapper;

import static org.apache.ibatis.jdbc.SqlBuilder.BEGIN;
import static org.apache.ibatis.jdbc.SqlBuilder.DELETE_FROM;
import static org.apache.ibatis.jdbc.SqlBuilder.SQL;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.scripting.xmltags.MixedSqlNode;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.scripting.xmltags.StaticTextSqlNode;

import com.github.abel533.mapper.MapperProvider;
import com.github.abel533.mapperhelper.EntityHelper;
import com.github.abel533.mapperhelper.MapperHelper;

public class SysMapperProvider extends MapperProvider {

    public SysMapperProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }

    public SqlNode deleteByIDS(MappedStatement ms) {
        Class<?> entityClass = getSelectReturnType(ms);
        Set<EntityHelper.EntityColumn> entityColumns = EntityHelper.getPKColumns(entityClass);
        EntityHelper.EntityColumn column = null;
        for (EntityHelper.EntityColumn entityColumn : entityColumns) {
            column = entityColumn;
            break;
        }
        
        List<SqlNode> sqlNodes = new ArrayList<SqlNode>();
        // 开始拼sql
        BEGIN();
        // delete from table
        DELETE_FROM(tableName(entityClass));
        // 得到sql
        String sql = SQL();
        // 静态SQL部分
        sqlNodes.add(new StaticTextSqlNode(sql + " WHERE " + column.getColumn() + " IN "));
        // 构造foreach sql
        SqlNode foreach = new ForEachSqlNode(ms.getConfiguration(), new StaticTextSqlNode("#{"
                + column.getProperty() + "}"), "ids", "index", column.getProperty(), "(", ")", ",");
        sqlNodes.add(foreach);
        return new MixedSqlNode(sqlNodes);
    }

}

 

 

第三步:Mapper都继承SysMapper接口

package com.jt.manage.mapper;

import java.util.List;
import org.apache.ibatis.annotations.Param;

import com.jt.manage.mapper.base.mapper.SysMapper;
import com.jt.manage.pojo.ItemCat;

public interface ItemCatMapper extends SysMapper<ItemCat>{

    /**
     * 根据ID查询商品分类数据,parentId = id(参数)
     * 
     * @param id
     * @return
     */
    //List<ItemCat> queryListById(@Param("id") Long id);

}

 

 

第四步:在mybatis-config.xml中配置插件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

	<settings>
		<!-- 开启驼峰自动映射 -->
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<!-- 二级缓存的总开关 -->
		<setting name="cacheEnabled" value="false" />
	</settings>

	<plugins>
		<!-- 分页插件:com.github.pagehelper为PageHelper类所在包名 -->
		<plugin interceptor="com.github.pagehelper.PageHelper">
			<!-- 方言 -->
			<property name="dialect" value="mysql" />
			<!-- 该参数默认为false -->
			<!-- 设置为true时,使用RowBounds分页会进行count查询,查询数据总条数 -->
			<property name="rowBoundsWithCount" value="true" />
		</plugin>
		
		<!-- 通用Mapper插件 -->
		<plugin interceptor="com.github.abel533.mapperhelper.MapperInterceptor">
			<!--主键自增回写方法,默认值MYSQL,详细说明请看文档 -->
			<property name="IDENTITY" value="MYSQL" />
			<!--通用Mapper接口,多个通用接口用逗号隔开 -->
			<property name="mappers" value="com.jt.manage.mapper.base.mapper.SysMapper" />
		</plugin>
	</plugins>

</configuration>

 

 

第五步:pojo文件加上注解

package com.jt.manage.pojo;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Table(name = "tb_item_cat")
public class ItemCat extends BasePojo{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    // 主键自增长策略
    private Long id;

    // 父分类ID=0时,代表的是一级的分类
    @Column(name = "parent_id")
    private Long parentId;

    private String name;

    // 状态。可选值:1(正常),2(删除)
    private Integer status;

    // 排列序号,表示同级分类的展现次序,如数值相等则按名称次序排列。取值范围:大于零的整数
    @Column(name = "sort_order")
    private Integer sortOrder;

    // 该分类是否为父分类,1为true,0为false
    @Column(name = "is_parent")
    private Boolean isParent;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getParentId() {
    return parentId;
    }

    public void setParentId(Long parentId) {
        this.parentId = parentId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public Integer getSortOrder() {
        return sortOrder;
    }

    public void setSortOrder(Integer sortOrder) {
        this.sortOrder = sortOrder;
    }

    public Boolean getIsParent() {
        return isParent;
    }

    public void setIsParent(Boolean isParent) {
        this.isParent = isParent;
    }

    // 扩展get方法,满足EasyUI的tree格式
    public String getText() {
        return getName();
    }

    public String getState() {
        return getIsParent() ? "closed" : "open";
    }

}

第六步:Service方法也跟着修改

package com.jt.manage.service;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jt.manage.mapper.ItemCatMapper;
import com.jt.manage.pojo.ItemCat;

@Service
public class ItemCatService {

	@Autowired
	private ItemCatMapper itemCatMapper;

    public List<ItemCat> queryListById(Long id) {
        //return this.itemCatMapper.queryListById(id);
    	ItemCat ic = new ItemCat();
    	ic.setParentId(id);
    	return this.itemCatMapper.select(ic);
    }
}

 

 

第七步:测试,控制台日志:

2015-05-08 15:47:41,105 [http-bio-8082-exec-1] [com.jt.manage.mapper.ItemCatMapper.select]-[DEBUG] ==>  Preparing: SELECT IS_PARENT ISPARENT,PARENT_ID PARENTID,STATUS,NAME,UPDATED,CREATED,SORT_ORDER SORTORDER,ID FROM tb_item_cat WHERE PARENT_ID = ? 
2015-05-08 15:47:41,182 [http-bio-8082-exec-1] [com.jt.manage.mapper.ItemCatMapper.select]-[DEBUG] ==> Parameters: 0(Long)
2015-05-08 15:47:41,262 [http-bio-8082-exec-1] [com.jt.manage.mapper.ItemCatMapper.select]-[DEBUG] <==      Total: 19

 

 

第八步:进一步抽取Service

BaseService.java

package com.jt.manage.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.jt.manage.mapper.base.mapper.SysMapper;

public abstract class BaseService<T> {

    @Autowired
    private SysMapper<T> sysMapper;
    
    //传统写法,Spring4以下版本
//    public abstract SysMapper<T> getSysMapper();
  /**
     * 根据主键查询数据
     * 
     * @param id
     * @return
     */
    public T queryById(Object id) {
        return this.sysMapper.selectByPrimaryKey(id);
    }

    /**
     * 根据条件查询,多条件之间是 and 关系
     * 
     * @param t
     * @return
     */
    public List<T> queryListByWhere(T t) {
        return this.sysMapper.select(t);
    }

    /**
     * 根据条件查询单条数据
     * 
     * @param t
     * @return
     */
    public T queryByWhere(T t) {
        List<T> list = queryListByWhere(t);
        if (list != null && !list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 查询所有数据
     * 
     * @return
     */
    public List<T> queryAll() {
        return this.sysMapper.select(null);
    }

    /**
     * 新增数据,使用全部字段
     * 
     * @param t
     */
    public void save(T t) {
        this.sysMapper.insert(t);
    }

    /**
  * 新增数据,使用不为null的字段
     * 
     * @param t
     */
    public void saveSelective(T t) {
        this.sysMapper.insertSelective(t);
    }

    /**
     * 根据id删除
     * 
     * @param id
     * @return
     */
    public Integer deleteById(Object id) {
        return this.sysMapper.deleteByPrimaryKey(id);
    }

    /**
     * 根据ids删除
     * 
     * @param ids
     * @return
     */
    public Integer deleteByIds(Object[] ids) {
        return this.sysMapper.deleteByIDS(ids);
    }

    /**
     * 根据条件删除
     * 
     * @param t
     */
    public Integer deleteByWhere(T t) {
        return this.sysMapper.delete(t);
    }

    /**
     * 根据主键id更新数据
     * 
     * @param t
     */
    public Integer update(T t) {
        return this.sysMapper.updateByPrimaryKey(t);
    }
    
    /**
     * 根据主键id更新数据
     * 
     * @param t
     */
    public Integer updateSelective(T t) {
        return this.sysMapper.updateByPrimaryKeySelective(t);
    }

}

 

 

第九步:改造ItemCatService

package com.jt.manage.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jt.manage.mapper.ItemCatMapper;
import com.jt.manage.pojo.ItemCat;

@Service
public class ItemCatService extends BaseService<ItemCat> {

	@Autowired
	private ItemCatMapper itemCatMapper;

    public List<ItemCat> queryListById(Long id) {
        //return this.itemCatMapper.queryListById(id);
    	ItemCat ic = new ItemCat();
    	ic.setParentId(id);
    	return this.itemCatMapper.select(ic);
    }
}

 

 

问题:当父类需要一个对象时,子类如何注入?

例如:BaseService中需要SysMapper对象。

传统方式:

在父类中声明:

public abstract SysMapper<T> getSysMapper();

在子类中实现这个方法:

public class ItemCatService extends BaseService<ItemCat> {
	@Autowired
	private ItemCatMapper itemCatMapper;

	public SysMapper<ItemCat> getSysMapper(){
		return itemcatMapper;
	}
……

注入方式:Spring4新加特性,通过泛型注入。

只需父类中声明:

public abstract class BaseService<T> {

    @Autowired
private SysMapper<T> sysMapper;
……

 

常见问题

 

 

spring和springmvc容器间的关系

Spring会创建一个WebApplicationContext上下文,称为容器 ,保存在 ServletContext中,key是 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。可以使用Spring提供的工具类取出上下文对象:

WebApplicationContextUtils.getWebApplicationContext(ServletContext); 

DispatcherServlet是一个Servlet,可以同时配置多个,每个DispatcherServlet有一个自己的上下文对象(SevletWebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文中的内容,但父上下文不能访问子上下文中的内容。 它也保存在 ServletContext中,key 是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。 当一个Request对象产生时,会把这个子上下文对象(SevletWebApplicationContext)保存在Request对象中,key是 DispatcherServlet.class.getName() + ".CONTEXT"。

可以使用工具类取出上下文对象:RequestContextUtils.getWebApplicationContext(request);  说明:Spring 并没有限制我们,必须使用父子上下文。我们可以自己决定如何使用。

父上下文容器中保存数据源、服务层、DAO层、事务的Bean。子上下文容器中保存MVC相关的Action的Bean。事务控制在服务层。由于父上下文容器不能访问子上下文容器中内容,事务的Bean在父上下文容器中,无法访问子上下文容器中内容,就无法对子上下文容器中Action进行AOP(事务)。

 

 

spring和springmvc都扫描了PageController

跟踪源码spring-beans中提供的DefaultListableBeanFactory中的392行

return StringUtils.toStringArray(this.beanDefinitionNames);

观察beanDefinitionNames可以看到在项目启动后,spring将Controller加载了。

Spring虽然扫描了Controller,但访问的请求无法拦截。sringmvc全部扫描,但service没有事务。

不想扫描多余的controller解决办法:

	<context:component-scan 
		base-package="com.jt.common.service,
					  com.jt.manage.service" />

 

 

mybatis中的“假接口”

映射文件的内容:ItemCatMapper.xml

<mapper namespace="com.jt.manage.mapper.ItemCatMapper">

	<select id="queryListById" parameterType="long" resultType="ItemCat">
		SELECT * FROM tb_item_cat WHERE parent_id = #{id}
	</select>
</mapper>

接口文件的内容:

package com.jt.manage.mapper;
public interface ItemCatMapper extends SysMapper<ItemCat>{
    List<ItemCat> queryListById(@Param("id") Long id);
}	

类中调用接口找映射文件中的sql,然后利用sqlSession提供方法来执行。

1) 获取接口,通过spring,spring和mybatis集成,配置接口扫描的目录。

2) 获取到这个接口的包路径和接口名称 等价于 映射文件中的命名空间,定位映射文件

3) 通过反射获取接口中的所有方法、返回值、参数,例如就可以获取到queryListById。这个名称就是映射文件中某个标签的id值。就找到要执行SQL语句。

4) 首先根据映射文件中找到的标签来判断,接口中返回值是一个List<Object>调用selectList,如果只是Object,调用selectOne。

源码分析:

如何执行一个查询

  1. SqlSession的实现类
  2. 初始化,通过sqlsession的getMapper方法获取Mapper接口的动态代理实例

    初始化获得sqlSession的实例对象,并将所有Mapper保存在一个knownMappers的Map中。其key就是包名.类名=映射文件中的命名空间。value存放MapperProxy代理类。
  3. 最终查询时还是调用sqlSession的方法selectList
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值