目标:
微服务中通过统一的接口实现Excel导入,模板需要提前设置好,
根据模板中的类和属性去往对应服务,通过反射生成实体类,
最后使用mybatis进行数据查询和插入操作。可以参考思路进行对应改造,
还有很多不完善地方,大家可以继续完善改造。
第一行:模板名称 # 服务名.bean
第二行(表头):列名 # 字段名
第三行开始:数据内容
import lombok.Data;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 通用model对象
*/
@Data
public class ModelObj {
/**
* model名称
*/
private String name;
/**
* model类名
*/
private String cls;
/**
* model列名
*/
private Map<String, Integer> colNames;
/**
* model数据
*/
private List<HashMap<String, Object>> data;
/**
* 验证通过数据
*/
private List<Object> sucData;
/**
* 验证失败数据
*/
private List<HashMap<String, Object>> failData;
}
@ApiOperation(value = "导入", notes = "信息")
@PostMapping(value = "/import")
@CrossOrigin
public Result<String> minio(@ApiParam(required = true, value = "文件") @RequestParam MultipartFile file) throws Exception {
//1、解析文件内容,获得实体
JLExcelUtil jlExcelUtil = new JLExcelUtil();
ModelObj modelObj = jlExcelUtil.importExcel("", file.getInputStream());
if (modelObj.getCls().equals("")) {
throw new DefineException("导入文件错误");
}
if (modelObj.getData() == null || modelObj.getData().size() == 0) {
throw new DefineException("导入文件中无数据");
}
//2、根据获取实体中服务名调用provider
String clsName = modelObj.getCls();
Result<String> result = new Result<>();
if (clsName.contains(".organization.") || clsName.contains(".org.")) {//organization服务
result = orgProvider.importData(modelObj);
} else if (clsName.contains(".safe.")) {//safe服务
result = safeProvider.importData(modelObj);
} else if (clsName.contains(".envpro.")) {//envpro服务
result = envproProvider.importData(modelObj);
} else if (clsName.contains(".equ.")) {//equ服务
result = equProvider.importData(modelObj);
} else if (clsName.contains(".edu.")) {//edu服务
result = eduProvider.importData(modelObj);
}
logger.info("结果:{}", JSON.toJSONString(result));
return result;
}
import com.zbzk.common.web.entity.ModelObj;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Excel相关处理
*/
public class JLExcelUtil<T> {
//日志操作类
private static final Logger log = LoggerFactory.getLogger(JLExcelUtil.class);
/**
* 工作簿中工作表最大数量,默认为255
* excel2003一个工作簿中最多有255个工作表
* 而在excel2007及以上的版本没有限制
*/
private static final int sheetTotal = 255;
/**
* Excel sheet最大行数,默认65536
* 在 Excel 97-2003 中,工作表的大小为 256 列 × 65,536 行。在 Excel 中,超出最大行列数单元格中的数据将会丢失。
* 在 Excel 2010 和 Excel 2007 中,工作表的大小为 16,384 列 × 1,048,576 行
*/
private static final int sheetRows = 65536;
/**
* 工作表中最大列数,默认 256
*/
private static final int sheetCols = 256;
/**
* 工作薄对象
*/
private Workbook wb;
/**
* 工作表对象
*/
private Sheet sheet;
/**
* 工作表名称
*/
private String sheetName;
/**
* 样式列表
*/
private Map<String, CellStyle> styles;
/**
* 导入导出数据列表
*/
private List<T> list;
/**
* 实体对象
*/
public Class<T> clazz;
public JLExcelUtil() {
}
/**
* 对excel表单指定表格索引名转换成list
*
* @param sheetName 第一个工作表名
* @param is 文件输入流
* @return 转换后结果集合
*/
public ModelObj importExcel(String sheetName, InputStream is) throws Exception {
ModelObj beanObj = new ModelObj();
//获取工作表
Sheet sheet = getSheet(sheetName, is);
//获取工作表行数
int rows = sheet.getPhysicalNumberOfRows();
if (rows >= 2) {//能够获取到实体名称和实体字段
List<HashMap<String, Object>> list = new ArrayList<>();
//获取实体名称
beanObj = getHeadCells(sheet);
//获取实体内容
for (int i = 2; i < rows; i++) {
// 从第3行开始取数据
Row row = sheet.getRow(i);
if (row.getPhysicalNumberOfCells() == 0) {//排除空行
continue;
}
HashMap<String, Object> maps = new HashMap<>();
for (Map.Entry<String, Integer> entry : beanObj.getColNames().entrySet()) {
maps.put(entry.getKey(), getCellValue(row, entry.getValue()));
}
list.add(maps);
}
beanObj.setData(list);
}
return beanObj;
}
/**
* 通过文件输入流获取工作表
* 如果传入了工作表名,按照表名取得;否则默认取得第一个工作表
*
* @param sheetName 工作表名
* @param is 文件输入流
* @return 工作表
* @throws IOException
*/
public Sheet getSheet(String sheetName, InputStream is) throws IOException {
Sheet sheet = null;
//将输入文件流转换为工作簿对象:Workbook
this.wb = WorkbookFactory.create(is);
// 如果指定sheet名,则取指定sheet中的内容.
if (StringUtils.isNotEmpty(sheetName)) {
sheet = wb.getSheet(sheetName);
} else {
// 如果传入的sheet名不存在则默认指向第1个sheet.
sheet = wb.getSheetAt(0);
}
if (sheet == null) {
throw new IOException("文件sheet不存在");
}
return sheet;
}
/**
* 获取模板第一行和第二行:
* 实体类名称和实体类字段
*
* @param sheet 工作表
* @return 实体类名称、实体类字段
* @throws IOException
*/
public ModelObj getHeadCells(Sheet sheet) throws IOException {
ModelObj modelObj = new ModelObj();
//获取第一行:实体类名称
Row clsName = sheet.getRow(0);
if (clsName.getPhysicalNumberOfCells() == 0) {
throw new IOException("模板格式不正确");
}
Map<String, Integer> clsObj = getCells(sheet, 0);
for (Map.Entry<String, Integer> map : clsObj.entrySet()) {
//排除掉空列,只保留有值的列
if (map.getKey() == "") {
continue;
}
String[] tmp = map.getKey().split("#");
if (tmp.length == 2) {
modelObj.setName(tmp[0]);
modelObj.setCls(tmp[1]);
}
}
//获取第二行:实体类字段
Row columnNames = sheet.getRow(1);
if (columnNames.getPhysicalNumberOfCells() == 0) {
throw new IOException("模板格式不正确");
}
Map<String, Integer> columnObj = getCells(sheet, 1);
Map<String, Integer> newColObj = new HashMap<>();
for (Map.Entry<String, Integer> map : columnObj.entrySet()) {
String[] tmp = map.getKey().split("#");
if (tmp.length == 2) {
newColObj.put(tmp[1], map.getValue());
}
}
modelObj.setColNames(newColObj);
return modelObj;
}
/**
* 获取一行的值
*
* @param sheet 工作表
* @param m 行号
* @return 该行中每列序号和值
*/
public Map<String, Integer> getCells(Sheet sheet, int m) {
Map<String, Integer> cellMap = new HashMap<>();
//获取第一行:实体类名称
Row row = sheet.getRow(m);
if (row.getPhysicalNumberOfCells() == 0) {
return null;//该行不存在任何元素
}
for (int i = 0; i < row.getPhysicalNumberOfCells(); i++) {
Cell cell = row.getCell(i);//判断列是否为空
if (StringUtil.isNotNull(cell)) {//列不为空时
String value = getCellValue(row, i).toString();
cellMap.put(value, i);
} else {//某列为空时
cellMap.put(null, i);
}
}
return cellMap;
}
/**
* 获取单元格值
*
* @param row 获取的行
* @param column 获取单元格列号
* @return 单元格值
*/
public Object getCellValue(Row row, int column) {
if (row == null) {
return null;
}
Object val = "";
try {
Cell cell = row.getCell(column);
if (StringUtil.isNull(cell)) {
return null;
}
switch (cell.getCellType()) {
case NUMERIC:
case FORMULA:
val = cell.getNumericCellValue();
if (HSSFDateUtil.isCellDateFormatted(cell)) {
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
val = sdf.format(val);
} else {
val = new BigDecimal(val.toString()); // 浮点格式处理
}
break;
case STRING:
val = cell.getStringCellValue();
break;
case BOOLEAN:
val = cell.getBooleanCellValue();
break;
case ERROR:
val = cell.getErrorCellValue();
break;
}
} catch (Exception e) {
return val;
}
return val;
}
}
(每个服务提供一个provider)
import com.zbzk.common.core.entity.vo.Result;
import com.zbzk.common.web.entity.ModelObj;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
*
* 导入信息
*
* @author jsonliu
* @since 2021/6/23
*/
@FeignClient(name = "organization")
public interface OrgProvider {
/**
* 导入数据
*
* @param modelObj:实体名称和实体数据
* @return 导入结果
*/
@PostMapping(value = "api/excel/importData")
Result<String> importData(@RequestBody ModelObj modelObj);
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义导出Excel数据注解
*
* @author jsonliu
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel
{
/**
* 导出时在excel中排序
*/
int sort() default Integer.MAX_VALUE;
/**
* 数据字典父ID
* @return
*/
long dicParentId() default -1L;
/**
* 字段是否是部门
* @return
*/
boolean isDepartment() default false;
/**
* 字段是否是用户
* @return
*/
boolean isUser() default false;
/**
* 字段是否是职员
* @return
*/
boolean isEmployee() default false;
/**
* 唯一性验证
* @return
*/
String unique() default "";
/**
* 导出到Excel中的名字.
*/
String name() default "";
/**
* 日期格式, 如: yyyy-MM-dd
*/
String dateFormat() default "";
}
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zbzk.common.core.common.BillTypeEnum;
import com.zbzk.common.core.entity.org.po.SysUser;
import com.zbzk.common.core.entity.po.org.dictionary.BaseDatatype;
import com.zbzk.common.core.entity.vo.Result;
import com.zbzk.common.core.util.Current;
import com.zbzk.common.core.util.DateUtils;
import com.zbzk.common.web.annotation.Excel;
import com.zbzk.common.web.entity.ModelObj;
import com.zbzk.common.web.entity.org.department.SysDepartmentVO;
import com.zbzk.common.web.entity.org.employee.SysEmployee;
import com.zbzk.common.web.utils.ReflectUtils;
import com.zbzk.sysadmin.organization.service.BaseDatatypeService;
import com.zbzk.sysadmin.organization.service.ExcelOperateService;
import com.zbzk.sysadmin.organization.service.SysDepartmentService;
import com.zbzk.sysadmin.organization.service.SysEmployeeService;
import com.zbzk.sysadmin.organization.service.impl.SysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.*;
@RestController
@RequestMapping("/api/excel")
@Api(value = "/api/excel", tags = "Excel公共操作接口")
@Slf4j
public class ExcelOperateController {
@Autowired
private ExcelOperateService excelService;
@Autowired
private SysDepartmentService sysDepartmentService;
@Autowired
private BaseDatatypeService baseDatatypeService;
@Autowired
private SysUserService sysUserService;
@Autowired
private SysEmployeeService sysEmployeeService;
private List<SysDepartmentVO> departmentVOS;
private List<BaseDatatype> dataTypes;
private List<SysUser> users;
private List<SysEmployee> employeeIdCard;
@ApiOperation(value = "导入", notes = "导入")
@PostMapping(value = "/importData")
public Result<String> importData(@RequestBody ModelObj modelObj) throws Exception {
Class<?> bean = Class.forName(modelObj.getCls()); //取得实体类
initBaseData(bean);//加载基础信息
setListData(modelObj, bean); //设置实体类数据转换
//数据验证失败
if (modelObj.getSucData().size() == 0)
return Result.fail("验证失败数据:" + JSON.toJSONString(modelObj.getFailData()));
//执行数据库操作
if (excelService.commonMapperBatchSave(bean, modelObj.getSucData())) {
return Result.success("数据导入成功:" + modelObj.getSucData().size() + "条,导入失败"
+ modelObj.getFailData().size() + "条。验证失败数据:" + JSON.toJSONString(modelObj.getFailData()));
}
return Result.fail("数据导入失败");
}
/**
* 获取实体类数据
*
* @param modelObj 实体类数据
* @param cls 类对象
* @return
* @throws Exception
*/
private void setListData(ModelObj modelObj, Class<?> cls) throws Exception {
List<Object> sucList = new ArrayList<>();
List<HashMap<String, Object>> failList = new ArrayList<>();
//生成List
for (HashMap<String, Object> maps : modelObj.getData()) {//遍历每一行元素
Object o = cls.getConstructor().newInstance();
boolean ok = true;//数据验证标志
//遍历每一列
for (Map.Entry<String, Object> entry : maps.entrySet()) {
//验证数据
if (!verifyData(entry.getKey(), entry.getValue())) {
ok = false;
break;
}
//完善补充信息
perfectData(o, entry.getKey(), entry.getValue());
}
//判断该行数据是否验证通过
if (!ok) {
failList.add(maps);
continue;
}
//添加默认值
defaultData(o, modelObj);
sucList.add(o);
}
modelObj.setSucData(sucList);
modelObj.setFailData(failList);
}
/**
* 初始化基础数据
*/
private void initBaseData(Class<?> cls) {
//数据字典获取
Field[] fields = ReflectUtils.getAllField(cls);
HashSet<Long> dicParentId = new HashSet<>();
for (Field field : fields) {
Excel excel = field.getAnnotation(Excel.class);
if (excel == null) continue;
//数据字典
if (field.getType() == Long.class) {
//获取所有字典父级ID
if (excel.dicParentId() != -1L) {
dicParentId.add(excel.dicParentId());
}
//加载部门基础信息
if (excel.isDepartment() && departmentVOS == null) {
departmentVOS = sysDepartmentService.selectList();
}
//加载人员信息,按照姓名正序
if (excel.isUser() && users == null) {
users = sysUserService.list(new QueryWrapper<SysUser>().lambda()
.eq(SysUser::getDelete, 0)
.gt(SysUser::getSfUserId, -1)
.orderByAsc(SysUser::getSfUserName));
}
}
//验证数据
if (field.getType() == String.class) {
if (excel.unique().equals("SysEmployee")) {
//按照身份证号码排序
employeeIdCard = sysEmployeeService.list(new QueryWrapper<SysEmployee>().lambda()
.eq(SysEmployee::getSfDelete, 0)
.orderByAsc(SysEmployee::getSfIdCard));
}
}
}
//查询dataType
if (dicParentId.size() > 0) {
dataTypes = baseDatatypeService.list(new QueryWrapper<BaseDatatype>().lambda()
.in(BaseDatatype::getSfParentId, dicParentId)
.ne(BaseDatatype::getSfDelete, 0));
}
}
/**
* 添加默认信息
* 默认信息:建立人、建立时间、修改人、修改时间、单据类型
*
* @param o
* @param modelObj
*/
private void defaultData(Object o, ModelObj modelObj) {
//登录人信息
String username = Current.getInstance().getUsername();
//建立人
setFieldValue(o, "sfCreator", username);
//修改人
setFieldValue(o, "sfMender", username);
//建立时间
setFieldValue(o, "sfCreateTime", new Date());
//修改时间
setFieldValue(o, "sfModifyTime", new Date());
}
/**
* 判断字段是否存在,存在则赋予值
*
* @param o
* @param fieldName
* @param val
*/
private void setFieldValue(Object o, String fieldName, Object val) {
//是否存在字段
Field field = ReflectionUtils.findField(o.getClass(), fieldName);
if (field != null) {
field.setAccessible(true);
ReflectionUtils.setField(field, o, val);
}
}
/**
* 加入注解值获取
* 设置枚举值
* @param o
* @param fieldName
* @param val
*/
private void setAnnFieldVal(Object o, String fieldName, Object val) {
//是否存在字段
Field field = ReflectionUtils.findField(o.getClass(), fieldName);
if (field != null) {
field.setAccessible(true);
//实际值是Long传入值是String :数据字典获取
if (field.getType() == Long.class && val instanceof String) {
Excel excel = field.getAnnotation(Excel.class);
Long l = -1L;
//数据字典
if (excel != null && excel.dicParentId() != -1L) {
l = getDicByName(excel.dicParentId(), val.toString());
}
//部门信息查询
if (excel != null && excel.isDepartment()) {
l = getDepartByName(val.toString());
}
//人员信息查询
if (excel != null && excel.isUser()) {
l = getUserByName(val.toString());
}
ReflectionUtils.setField(field, o, l);
return;
}
if(field.getType()==Date.class){
ReflectionUtils.setField(field, o, DateUtils.parseDate(val));
return;
}
ReflectionUtils.setField(field, o, val);
}
}
/**
* 获取数据字典值
*
* @param parentId
* @param dicName
* @return
*/
private Long getDicByName(long parentId, String dicName) {
for (BaseDatatype datatype : dataTypes) {
if (parentId == datatype.getSfParentId() && dicName.equals(datatype.getSfName())) {
return datatype.getSfTypeId();
}
}
return -1L;
}
/**
* 根据用户姓名查找用户ID
*
* @param name
* @return
*/
private Long getUserByName(String name) {
SysUser user = new SysUser();
user.setSfUserName(name);
int index = Collections.binarySearch(users, user, new Comparator<SysUser>() {
@Override
public int compare(SysUser o1, SysUser o2) {
return o1.getSfUserName().compareTo(o2.getSfUserName());
}
});
if (index < 0) return -1L;
return users.get(index).getSfUserId();
}
/**
* 根据职员身份证号码查询职员
*
* @param val
* @return
*/
private SysEmployee getEmpByIdCard(String val) {
if (employeeIdCard == null || employeeIdCard.size() == 0) return null;
SysEmployee employee = new SysEmployee();
employee.setSfIdCard(val);
int index = Collections.binarySearch(employeeIdCard, employee, new Comparator<SysEmployee>() {
@Override
public int compare(SysEmployee o1, SysEmployee o2) {
return o1.getSfIdCard().compareTo(o2.getSfIdCard());
}
});
if (index < 0) return null;
return employeeIdCard.get(index);
}
/**
* 根据部门名称查询部门ID
*
* @param departName
* @return
*/
private Long getDepartByName(String departName) {
for (SysDepartmentVO vo : departmentVOS) {
if (vo.getSfDepartmentName().equals(departName)) {
return vo.getSfDepartmentId();
}
}
return -1L;
}
/**
* 补充完善实体信息
* 2、部门、人员、职员信息
* 3、性别、出生年月等计算
* 4、字典表
*/
private void perfectData(Object o, String fieldName, Object val) throws ParseException {
switch (fieldName) {
case "sfIdCard":
setFieldValue(o, fieldName, val);//存储身份证
Map<String, String> map = DateUtils.getBirAgeSex(val.toString());
//性别
setFieldValue(o, "sfSex", Integer.parseInt(map.get("sexCode")));
//出生年月
setFieldValue(o, "sfBirthday", DateUtils.string2Date(map.get("birthday"), "yyyy-MM-dd HH:mm:ss"));
break;
default:
//默认设置
setAnnFieldVal(o, fieldName, val);
break;
}
}
/**
* 校验数据
* 一次性传入全部条件,获取list结果集合(重复记录集合)
* 1、唯一性校验:身份证、手机号码
*/
private boolean verifyData(String fieldName, Object val) {
switch (fieldName) {
case "sfMobilephone"://验证手机号码
SysEmployee phone = getEmpByPhone(val.toString());
if (phone != null) return false;
break;
case "sfIdCard": //验证身份证号码
SysEmployee idCard = getEmpByIdCard(val.toString());
if (idCard != null) return false;
break;
default:
break;
}
return true;
}
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.zbzk.sysadmin.organization.service.ExcelOperateService;
import com.zbzk.sysadmin.organization.util.SpringContextUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.List;
@Service
public class ExcelOperateServiceImpl implements ExcelOperateService {
/**
* 获取bean对应的mapper类
* @param bean 数据实体类
* @return mapperServiceBean
*/
private Object getMapperServiceBean(Class<?> bean){
Object mapperServiceBean =null;
//1、获取mapper的class
//SqlHelper.table 取得mybatis-plus的TableInfo:mapper、表、主键、字段
String mapperPath = SqlHelper.table(bean).getCurrentNamespace();
Class<?> dataMapperClass = null;
try {
dataMapperClass = Class.forName(mapperPath);
mapperServiceBean = SpringContextUtil.getBean(dataMapperClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return mapperServiceBean;
}
/**
* 构造查询方法
* name :like;
*
* @param ew
*/
private void getQueryWrapper(QueryWrapper ew){
}
/**
* 单个保存方法
* @param bean 数据实体类
* @param dataBean 实体类数据
* @return
*/
@Override
public boolean commonMapperSave(Class<?> bean, Object dataBean) {
//获取serviceBean
Object mapperServiceBean = getMapperServiceBean(bean);
try {
//3、反射工具类:获取操作方法(参数:class类、方法名称、参数类型)
Method mapperServiceBeanMethod = ReflectionUtils.findMethod(mapperServiceBean.getClass(), "insert", Object.class);
//4、反射工具类:执行操作方法(参数:操作方法、执行方法对象、参数值)
ReflectionUtils.invokeMethod(mapperServiceBeanMethod, mapperServiceBean, dataBean);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
@Transactional
public boolean commonMapperBatchSave(Class<?> bean, List<Object> list) {
//获取serviceBean
Object mapperServiceBean = getMapperServiceBean(bean);
try {
//3、反射工具类:获取操作方法(参数:class类、方法名称、参数类型)
Method mapperServiceBeanMethod = ReflectionUtils.findMethod(mapperServiceBean.getClass(), "insert", Object.class);
//4、反射工具类:执行操作方法(参数:操作方法、执行方法对象、参数值)
for(Object dataBean:list){
ReflectionUtils.invokeMethod(mapperServiceBeanMethod, mapperServiceBean, dataBean);
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public List<Object> commonMapperSelect(Class<?> bean) {
//获取serviceBean
Object mapperServiceBean = getMapperServiceBean(bean);
try {
QueryWrapper ew = new QueryWrapper();
ew.setEntity(bean);//???
//构造查询条件
// ????
Method mapperServiceBeanMethod = ReflectionUtils.findMethod(mapperServiceBean.getClass(), "selectList", QueryWrapper.class);
// 执行方法
Object obj = ReflectionUtils.invokeMethod(mapperServiceBeanMethod, mapperServiceBean, ew);
if(obj!=null){
return (List<Object>)obj;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}