基于mybatis的BaseDao及BaseService深度结合

mybatis帮助程序猿省去了很多工作了,需要结合好BaseDao与BaseService,这里就提供下我所使用的BaseXXX。

前提,mybatis的映射文件是采用mybatis-generator自动生成的(mybatis-generator使用方法

1、BaseDao,我们知道在mybatis与SpringMVC结合的时候,Dao层只需要写interface即可,剩下的实现工作将由mybatis自动为我们实现,这个BaseDao省去interface这层,采用SpringMvc的@Repository标签进行注入管理,上代码:

import java.io.Serializable;  
import java.lang.reflect.InvocationTargetException;  
import java.util.HashMap;  
import java.util.List;  
import java.util.Map;  
  
import org.apache.commons.beanutils.PropertyUtils;  
import org.apache.ibatis.session.RowBounds;  
import org.apache.ibatis.session.SqlSessionFactory;  
import org.mybatis.spring.support.SqlSessionDaoSupport;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Repository;  
  
import com.alibaba.dubbo.common.utils.CollectionUtils;  
import com.github.pagehelper.PageHelper;  
import com.github.pagehelper.PageInfo;  
//工具类  
import com.ivan.core.util.GenericsUtils;  
//分页Form  
import com.ivan.core.util.page.PageForm;  
  
@Repository("baseDao")  
public class BaseDao<T, PK extends Serializable> extends SqlSessionDaoSupport implements Serializable {  
      
    private static final long serialVersionUID = 7623507504198633838L;  
  
    private final String POSTFIX = "Dao";  
  
    private final String _INSERT = ".insert";  
  
    private final String _INSERTSELECTIVE = ".insertSelective";  
  
    private final String _SELECTBYPRIMARYKEY = ".selectByPrimaryKey";  
  
    private final String _UPDATEBYPRIMARYKEY = ".updateByPrimaryKey";  
  
    private final String _UPDATEBYPRIMARYKEYSELECTIVE = ".updateByPrimaryKeySelective";  
  
    private final String _DELETEBYPRIMARYKEY = ".deleteByPrimaryKey";  
      
    @Autowired  
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {  
        super.setSqlSessionFactory(sqlSessionFactory);  
    }  
    /*GenericsUtils为工具类,请见下方代码 
          泛型获得XXXEntity,将其转换为XXXEntityDao,具体操作替换掉Entity变成XXXDao,对应Mapper.xml中的namespace命名 
        */  
    @SuppressWarnings({ "unchecked", "rawtypes" })  
    public String getNampSpace() {  
        Class<T> clazz = (Class)GenericsUtils.getSuperClassGenricType(this.getClass());  
        String simpleName = clazz.getSimpleName() + POSTFIX;  
        return simpleName;  
    }  
      
    public int insert(T entity) {  
        return getSqlSession().insert(  
                (this.getNampSpace().contains("Entity") ? this.getNampSpace().replace("Entity", "")  
                        : this.getNampSpace()) + _INSERT, entity);  
    }  
      
      
    public int insertSelective(T record) {  
        return getSqlSession().insert(  
                (this.getNampSpace().contains("Entity") ? this.getNampSpace().replace("Entity", "")  
                        : this.getNampSpace()) + _INSERTSELECTIVE, record);  
    }  
  
    public T selectByPrimaryKey(PK id) {  
        return getSqlSession().selectOne(  
                (this.getNampSpace().contains("Entity") ? this.getNampSpace().replace("Entity", "")  
                        : this.getNampSpace()) + _SELECTBYPRIMARYKEY, id);  
    }  
  
      
    public int updateByPrimaryKey(T record) {  
        return getSqlSession().update(  
                (this.getNampSpace().contains("Entity") ? this.getNampSpace().replace("Entity", "")  
                        : this.getNampSpace()) + _UPDATEBYPRIMARYKEY, record);  
    }  
  
    public int updateByPrimaryKeySelective(T record) {  
        return getSqlSession().update(  
                (this.getNampSpace().contains("Entity") ? this.getNampSpace().replace("Entity", "")  
                        : this.getNampSpace()) + _UPDATEBYPRIMARYKEYSELECTIVE, record);  
    }  
  
    public int deleteByPrimaryKey(PK id) {  
        return getSqlSession().delete(  
                (this.getNampSpace().contains("Entity") ? this.getNampSpace().replace("Entity", "")  
                        : this.getNampSpace()) + _DELETEBYPRIMARYKEY, id);  
    }  
  
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    public PageInfo<T> pageFind(String statementKey, PageForm pageForm, Object parameter,  
            Boolean isSimplePage) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {  
        Map params = new HashMap();  
        if (parameter != null) {  
            if (parameter instanceof Map) {  
                params.putAll((Map) parameter);  
            } else {  
                Map parameterObject = PropertyUtils.describe(parameter);  
                params.putAll(parameterObject);  
            }  
        }  
        PageHelper.startPage(pageForm.getPage(), pageForm.getRows());  
        List<T> list = getSqlSession().selectList(statementKey, params);  
        PageInfo<T> pageInfo = new PageInfo(list);  
  
        return pageInfo;  
    }  
  
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    public List<T> findTop(int top, String statementKey, Object parameter) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {  
        Map params = new HashMap();  
        if (parameter != null) {  
            if (parameter instanceof Map) {  
                params.putAll((Map) parameter);  
            } else {  
                Map parameterObject = PropertyUtils.describe(parameter);  
                params.putAll(parameterObject);  
            }  
        }  
        List<T> list = getSqlSession().selectList(statementKey, params, new RowBounds(0, top));  
        return list;  
    }  
  
    public T findTopOne(String statementKey, Object parameter) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {  
        List<T> list = findTop(1, statementKey, parameter);  
        return CollectionUtils.isEmpty(list) ? null : list.get(0);  
    }  
      
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    public <M> PageInfo<M> pageFindModel(String statementKey, PageForm pageForm, Object parameter) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {  
        Map params = new HashMap();  
        if (parameter != null) {  
            if (parameter instanceof Map) {  
                params.putAll((Map) parameter);  
            } else {  
                Map parameterObject = PropertyUtils.describe(parameter);  
                params.putAll(parameterObject);  
            }  
        }  
        PageHelper.startPage(pageForm.getPage(), pageForm.getRows());  
        List<M> list = getSqlSession().selectList(statementKey, params);  
        PageInfo<M> pageInfo = new PageInfo(list);  
  
        return pageInfo;  
    }  
}  

2、泛型工具类,GenericsUtils:

import java.lang.reflect.Field;  
import java.lang.reflect.Method;  
import java.lang.reflect.ParameterizedType;  
import java.lang.reflect.Type;  
import java.util.ArrayList;  
import java.util.List;  
import java.util.Random;  
  
import javax.servlet.http.HttpSession;  
  
import org.springframework.web.context.request.RequestContextHolder;  
import org.springframework.web.context.request.ServletRequestAttributes;  
  
/** 
 * 泛型工具类 
 *  
 * @author <a href="http://www.blogjava.net/lishunli/" 
 *         target="_jeecg">ShunLi</a> 
 * @notes Created on 2010-1-21<br> 
 *        Revision of last commit:$Revision: 1.1 $<br> 
 *        Author of last commit:$Author: ghp $<br> 
 *        Date of last commit:$Date: 2010-01-25 16:48:17 +0800 (周一, 25 一月 2010) 
 *        $<br> 
 *        <p> 
 */  
public class GenericsUtils {  
    /** 
     * 通过反射,获得指定类的父类的泛型参数的实际类型. 如BuyerServiceBean extends DaoSupport<Buyer> 
     *  
     * @param clazz 
     *            clazz 需要反射的类,该类必须继承范型父类 
     * @param index 
     *            泛型参数所在索引,从0开始. 
     * @return 范型参数的实际类型, 如果没有实现ParameterizedType接口,即不支持泛型,所以直接返回 
     *         <code>Object.class</code> 
     */  
    public static Class getSuperClassGenricType(Class clazz, int index) {  
        Type genType = clazz.getGenericSuperclass();// 得到泛型父类  
        // 如果没有实现ParameterizedType接口,即不支持泛型,直接返回Object.class  
        if (!(genType instanceof ParameterizedType)) {  
            return Object.class;  
        }  
        // 返回表示此类型实际类型参数的Type对象的数组,数组里放的都是对应类型的Class, 如BuyerServiceBean extends  
        // DaoSupport<Buyer,Contact>就返回Buyer和Contact类型  
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();  
        if (index >= params.length || index < 0) {  
            throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));  
        }  
        if (!(params[index] instanceof Class)) {  
            return Object.class;  
        }  
        return (Class) params[index];  
    }  
  
    /** 
     * 通过反射,获得指定类的父类的第一个泛型参数的实际类型. 如BuyerServiceBean extends DaoSupport<Buyer> 
     *  
     * @param clazz 
     *            clazz 需要反射的类,该类必须继承泛型父类 
     * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口,即不支持泛型,所以直接返回 
     *         <code>Object.class</code> 
     */  
    @SuppressWarnings("unchecked")  
    public static Class getSuperClassGenricType(Class clazz) {  
        return getSuperClassGenricType(clazz, 0);  
    }  
  
    /** 
     * 通过反射,获得方法返回值泛型参数的实际类型. 如: public Map<String, Buyer> getNames(){} 
     *  
     * @param Method 
     *            method 方法 
     * @param int index 泛型参数所在索引,从0开始. 
     * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口,即不支持泛型,所以直接返回 
     *         <code>Object.class</code> 
     */  
    @SuppressWarnings("unchecked")  
    public static Class getMethodGenericReturnType(Method method, int index) {  
        Type returnType = method.getGenericReturnType();  
        if (returnType instanceof ParameterizedType) {  
            ParameterizedType type = (ParameterizedType) returnType;  
            Type[] typeArguments = type.getActualTypeArguments();  
            if (index >= typeArguments.length || index < 0) {  
                throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));  
            }  
            return (Class) typeArguments[index];  
        }  
        return Object.class;  
    }  
  
    /** 
     * 通过反射,获得方法返回值第一个泛型参数的实际类型. 如: public Map<String, Buyer> getNames(){} 
     *  
     * @param Method 
     *            method 方法 
     * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口,即不支持泛型,所以直接返回 
     *         <code>Object.class</code> 
     */  
    @SuppressWarnings("unchecked")  
    public static Class getMethodGenericReturnType(Method method) {  
        return getMethodGenericReturnType(method, 0);  
    }  
  
    /** 
     * 通过反射,获得方法输入参数第index个输入参数的所有泛型参数的实际类型. 如: public void add(Map<String, 
     * Buyer> maps, List<String> names){} 
     *  
     * @param Method 
     *            method 方法 
     * @param int index 第几个输入参数 
     * @return 输入参数的泛型参数的实际类型集合, 如果没有实现ParameterizedType接口,即不支持泛型,所以直接返回空集合 
     */  
    @SuppressWarnings("unchecked")  
    public static List<Class> getMethodGenericParameterTypes(Method method, int index) {  
        List<Class> results = new ArrayList<Class>();  
        Type[] genericParameterTypes = method.getGenericParameterTypes();  
        if (index >= genericParameterTypes.length || index < 0) {  
            throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));  
        }  
        Type genericParameterType = genericParameterTypes[index];  
        if (genericParameterType instanceof ParameterizedType) {  
            ParameterizedType aType = (ParameterizedType) genericParameterType;  
            Type[] parameterArgTypes = aType.getActualTypeArguments();  
            for (Type parameterArgType : parameterArgTypes) {  
                Class parameterArgClass = (Class) parameterArgType;  
                results.add(parameterArgClass);  
            }  
            return results;  
        }  
        return results;  
    }  
  
    /** 
     * 通过反射,获得方法输入参数第一个输入参数的所有泛型参数的实际类型. 如: public void add(Map<String, Buyer> 
     * maps, List<String> names){} 
     *  
     * @param Method 
     *            method 方法 
     * @return 输入参数的泛型参数的实际类型集合, 如果没有实现ParameterizedType接口,即不支持泛型,所以直接返回空集合 
     */  
    @SuppressWarnings("unchecked")  
    public static List<Class> getMethodGenericParameterTypes(Method method) {  
        return getMethodGenericParameterTypes(method, 0);  
    }  
  
    /** 
     * 通过反射,获得Field泛型参数的实际类型. 如: public Map<String, Buyer> names; 
     *  
     * @param Field 
     *            field 字段 
     * @param int index 泛型参数所在索引,从0开始. 
     * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口,即不支持泛型,所以直接返回 
     *         <code>Object.class</code> 
     */  
    @SuppressWarnings("unchecked")  
    public static Class getFieldGenericType(Field field, int index) {  
        Type genericFieldType = field.getGenericType();  
  
        if (genericFieldType instanceof ParameterizedType) {  
            ParameterizedType aType = (ParameterizedType) genericFieldType;  
            Type[] fieldArgTypes = aType.getActualTypeArguments();  
            if (index >= fieldArgTypes.length || index < 0) {  
                throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));  
            }  
            return (Class) fieldArgTypes[index];  
        }  
        return Object.class;  
    }  
  
    /** 
     * 通过反射,获得Field泛型参数的实际类型. 如: public Map<String, Buyer> names; 
     *  
     * @param Field 
     *            field 字段 
     * @param int index 泛型参数所在索引,从0开始. 
     * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口,即不支持泛型,所以直接返回 
     *         <code>Object.class</code> 
     */  
    @SuppressWarnings("unchecked")  
    public static Class getFieldGenericType(Field field) {  
        return getFieldGenericType(field, 0);  
    }  
/** 
 * 根据实体得到实体的所有属性 
 * @param objClass 
 * @return 
 * @throws ClassNotFoundException 
 */  
    public static String[] getColumnNames(String objClass) throws ClassNotFoundException {  
        String[] wageStrArray = null;  
        if (objClass != null) {  
            Class class1 = Class.forName(objClass);  
            Field[] field = class1.getDeclaredFields();// 这里便是获得实体Bean中所有属性的方法  
            StringBuffer sb = new StringBuffer();  
            for (int i = 0; i < field.length; i++) {// 这里不多说了  
  
                sb.append(field[i].getName());  
  
                // 这是分割符 是为了去掉最后那个逗号  
  
                // 比如 如果不去最后那个逗号 最后打印出来的结果是 "id,name,"  
  
                // 去了以后打印出来的是 "id,name"  
                if (i < field.length - 1) {  
                    sb.append(",");  
  
                }  
            }  
  
            // split(",");这是根据逗号来切割字符串使字符串变成一个数组  
  
            wageStrArray = sb.toString().split(",");  
            return wageStrArray;  
        } else {  
            return wageStrArray;  
        }  
    }  
    public static Object[] field2Value(Field[] f, Object o) throws Exception {  
        Object[] value = new Object[f.length];  
        for (int i = 0; i < f.length; i++) {  
            value[i] = f[i].get(o);  
        }  
        return value;  
    }  
    /** 
     * returns the current http session object 
     *  
     * @return session 
     */  
    public HttpSession getSession() {     
        HttpSession session=null;  
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();  
        HttpSession contextSess = attr == null ? session : attr.getRequest().getSession(true);  
          
        return contextSess;   
    }  
    /** 
     * 得到实体类 
     * @param objClass 实体类包含包名 
     * @return 
     */  
     public static  Class getEntityClass(String objClass){  
         Class entityClass = null;  
        try {  
            entityClass = Class.forName(objClass);  
        } catch (ClassNotFoundException e) {              
            e.printStackTrace();  
        }   
         return entityClass;  
     }    
       
     /** 
         * 定义字符集 
         * @param  
         * @return 
         */  
    private static char[] chars = { '0', '1', '2', '3', '4', '5', '6', '7',   
             '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',   
             'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',   
             'y', 'z', 'A', 'B','C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',   
             'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',   
             'Z'};    //72个字符集   
  
           /**  
           *  
           * @param passLength  
           *            随机密码长度  
           * @param count  
           *            随机密码个数  
           * @return 随机密码数组  
           */   
           public static String getPasswords(int passLength) {   
            String passwords = "";// 新建一个长度为指定需要密码个数的字符串数组   
            Random random = new Random();   
            StringBuilder password = new StringBuilder("");// 保存生成密码的变量   
            for (int m = 1; m <= passLength; m++) {// 内循环 从1开始到密码长度 正式开始生成密码   
              password.append(chars[random.nextInt(62)]);// 为密码变量随机增加上面字符中的一个   
            }   
            passwords = password.toString();// 将生成出来的密码赋值给密码数组   
            return passwords;   
           }   
  
  
} 

3、BaseService接口,为什么这层要选择接口来实现呢?有很多需要前后分离的应用,暴露的服务就是接口暴露Service层,所以采用接口。

import java.io.Serializable;  
import java.lang.reflect.InvocationTargetException;  
import java.util.List;  
  
@SuppressWarnings("hiding")  
public interface BaseService<T, Serializable> {  
      
    public int insert(T record);  
    public int insertSelective(T record);  
    public T selectByPrimaryKey(String id);  
    public int updateByPrimaryKey(T record);  
    public int updateByPrimaryKeySelective(T record);  
    public int deleteByPrimaryKey(String id);  
    public List<T> findTop(int top, String statementKey, Object parameter) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException;  
    public T findTopOne(String statementKey, Object parameter) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException;  
}  

4、BaseService接口的实现类BaseServiceImpl,需要注入BaseDao(其中必须对BaseDao进行set,否则无法获取具体泛型)

import java.io.Serializable;  
import java.lang.reflect.InvocationTargetException;  
import java.util.List;  
  
import org.springframework.beans.factory.annotation.Autowired;  
  
import com.alibaba.dubbo.config.annotation.Service;  
import com.ivan.api.base.BaseService;  
import com.ivan.base.BaseDao;  
  
@Service  
public abstract class BaseServiceImpl<T> implements BaseService<T, Serializable>{  
      
    @Autowired  
    private BaseDao<T, Serializable> baseDao;  
      
    public BaseDao<T, Serializable> getBaseDao() {  
        return baseDao;  
    }  
    public void setBaseDao(BaseDao<T, Serializable> baseDao) {  
        this.baseDao = baseDao;  
    }  
  
    public int insert(T entity) {  
        return baseDao.insert(entity);  
    }  
  
    public int insertSelective(T record) {  
        return baseDao.insertSelective(record);  
    }  
  
    public T selectByPrimaryKey(String id) {  
        return baseDao.selectByPrimaryKey(id);  
    }  
  
    public int updateByPrimaryKey(T record) {  
        return baseDao.updateByPrimaryKey(record);  
    }  
  
    public int updateByPrimaryKeySelective(T record) {  
        return baseDao.updateByPrimaryKeySelective(record);  
    }  
  
    public int deleteByPrimaryKey(String id) {  
        return baseDao.deleteByPrimaryKey(id);  
    }  
  
    public List<T> findTop(int top, String statementKey, Object parameter) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {  
        return baseDao.findTop(top, statementKey, parameter);  
    }  
  
    public T findTopOne(String statementKey, Object parameter) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {  
        return baseDao.findTopOne(statementKey, parameter);  
    }  
}  

5、Mapper.xml文件的定义,需要注意的是namespace的命名,会通过这个命名找到具体的mapper文件,进行数据的操作。

<?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="UserDao" >  
  <resultMap id="BaseResultMap" type="com.ivan.entity.UserEntity" >  
    <id column="id" property="id" jdbcType="VARCHAR" />  
    <result column="name" property="name" jdbcType="VARCHAR" />  
    <result column="age" property="age" jdbcType="INTEGER" />  
  </resultMap>  
  <sql id="Base_Column_List" >  
    id, name, age  
  </sql>  
    
  <select id="selectAll" resultMap="BaseResultMap">  
    select  
    <include refid="Base_Column_List" />  
    from user  
  </select>  
    
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="String" >  
    select   
    <include refid="Base_Column_List" />  
    from user  
    where id = #{id,jdbcType=INTEGER}  
  </select>  
  <delete id="deleteByPrimaryKey" parameterType="String" >  
    delete from user  
    where id = #{id,jdbcType=INTEGER}  
  </delete>  
  <insert id="insert" parameterType="com.ivan.entity.UserEntity" >  
    insert into user (id, name, age  
      )  
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}  
      )  
  </insert>  
  <insert id="insertSelective" parameterType="com.ivan.entity.UserEntity" >  
    insert into user  
    <trim prefix="(" suffix=")" suffixOverrides="," >  
      <if test="id != null" >  
        id,  
      </if>  
      <if test="name != null" >  
        name,  
      </if>  
      <if test="age != null" >  
        age,  
      </if>  
    </trim>  
    <trim prefix="values (" suffix=")" suffixOverrides="," >  
      <if test="id != null" >  
        #{id,jdbcType=VARCHAR},  
      </if>  
      <if test="name != null" >  
        #{name,jdbcType=VARCHAR},  
      </if>  
      <if test="age != null" >  
        #{age,jdbcType=INTEGER},  
      </if>  
    </trim>  
  </insert>  
  <update id="updateByPrimaryKeySelective" parameterType="com.ivan.entity.UserEntity" >  
    update user  
    <set >  
      <if test="name != null" >  
        name = #{name,jdbcType=VARCHAR},  
      </if>  
      <if test="age != null" >  
        age = #{age,jdbcType=INTEGER},  
      </if>  
    </set>  
    where id = #{id,jdbcType=VARCHAR}  
  </update>  
  <update id="updateByPrimaryKey" parameterType="com.ivan.entity.UserEntity" >  
    update user  
    set name = #{name,jdbcType=VARCHAR},  
      age = #{age,jdbcType=INTEGER}  
    where id = #{id,jdbcType=VARCHAR}  
  </update>  
</mapper>  

6、具体的使用方法:

a、定义UserDao:

@Repository("userDao")  
public class UserDao extends BaseDao<UserEntity, Serializable>{  
  
    /** 
     *  
     */  
    private static final long serialVersionUID = 9152785684346322571L;  
  
} 

b、定义UserService接口

public interface UserService extends BaseService<UserEntity, Serializable>{  
          
}  

c、实现UserService接口

@Service  
public class UserServiceImpl extends BaseServiceImpl<UserEntity> implements UserService{  
      
} 

d、调用UserService接口

@Controller  
@RequestMapping("/user")  
public class UserController {  
      
    @SuppressWarnings("unused")  
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);  
      
    @Reference  
    private UserService userService;  
}

猜你喜欢

转载自my.oschina.net/gaoenwei/blog/1811003