问题描述
一个excel中有两个sheet页,第一个sheet页保存的是本月的数据,第二个sheet页保存的是次月的数据,两个sheet页中的数据都分别对应着数据库中不同的两张表,如何实现excel往数据库的导入呢。
问题分析
1 excel数据解析:
使用POI或者JXL
2 数据映射
因为两个sheet页分别对应着不同的两张表,就涉及挑数这个问题,要分别处理
3 数据保存:
用hibernate保存对象即可
解决方案
根据分析问题分析,我们很容易的就想到一种解决办法
本月sheet页:解析数据->数据映射->保存数据
次月sheet页:解析数据->数据映射->保存数据
要是在多个sheet页怎么办?继续如法炮制?
我的方案
首先解析可以单独抽出来,保存也可以单独抽出来,唯一增加的是数据映射。
基于此:我们首先构建数据解析的方法:
/**
* 将excel读入到Map
* key为sheet页名称,value为将exceld单元格解析成的二维数据
* @param file
* @return
*/
private static Map<String,String[][]> reader(File file){
Map<String,String[][]> map=new HashMap<String,String[][]>();
//可以根据sheet页名称作循环解析
map.put("excelService4CurrentMonth", null);
map.put("excelService4CNextMonth", null);
return map;
}
保存方法:我们就建立一个保存的service.
package com.springIoc.service;
import com.springIoc.mapper.IExcelMapper;
/**
* excel服务类
* @author Administrator
*
*/
public class ExcelServer {
/**excel封装类,作解耦合使用*/
private IExcelMapper excelMapper;
/**excel返回的二维数组*/
private String[][] values;
public String[][] getValues() {
return values;
}
public void setValues(String[][] values) {
this.values = values;
}
public IExcelMapper getExcelMapper() {
return excelMapper;
}
public void setExcelMapper(IExcelMapper excelMapper) {
this.excelMapper = excelMapper;
}
/**可以通过hibernate保存方法实现数组的保存*/
public void save(String[][] values){
Object obj=excelMapper.mappering(values);
System.out.println(obj+"保存成功");
}
}
可以看到上述代码中有个叫IExcelMapper的接口,他的作用就是把二维数组中的数据转化为hibernate可保存的对象。
具体怎么处理要看他的实现类了。本月的返回本月封装好的对象,次月返回次月封装好的对象。
package com.springIoc.mapper;
/**
* excel映射接口
* @author Administrator
*
*/
public interface IExcelMapper {
public abstract Object mappering(String[][] values);
}
他的实现类做的就是数据映射
package com.springIoc.mapper.impl;
import com.springIoc.mapper.IExcelMapper;
/**
* 本月数据封装
* @author yj.shi
*
*/
public class ExcelMapper4CurrentMonth implements IExcelMapper{
@Override
public Object mappering(String[][] values) {
System.out.println("本月数据封装");
return "本月数据";
}
}
在service中调用接口,是不是就实现了数据的解耦呢?service跟数据映射类(ExcelMapper4CurrentMonth)是不是就可以随便拆开用了。
实现解耦了,下一步要做的就是对应关系,我哪知道哪个servcie中的ExcelMapper是哪一个?也许我们可以自己写对应逻辑。不过我觉得可行的方案是利用Spring的Ioc思想。
控制翻转:不是我那个service要找哪个mapper了,而是我哪个mapper要找哪个service。不是你要找我,而是我要找你,这样你就不用写那复杂的对应关系了。从你要找变为去找你,你是不就轻松多了呢。
依赖注入:注入的是啥?是依赖引用对象的注入。IExcelMapper是个引用的声明,我怎么注入他要引用的对象呢?
很简单,写个properites文件,说明他们的对应关系。
#本月excel映射
excelMapper4CurrentMonth=com.springIoc.mapper.impl.ExcelMapper4CurrentMonth
#次月excel映射
excelMapper4NextMonth=com.springIoc.mapper.impl.ExcelMapper4NextMonth
excelService4CurrentMonth=com.springIoc.service.ExcelServer
excelService4CNextMonth=com.springIoc.service.ExcelServer
excelService4CurrentMonth.excelMapper=excelMapper4CurrentMonth
excelService4CNextMonth.excelMapper=excelMapper4NextMonth
有了对应关系。下一步就是怎么来处理了。spring是个容器,对象的创建,依赖关系的建立最好要交给sring容器去做。下面就写一个spring容器。
我们根据上边的properites写好映射类就行了。
package com.springIoc.container;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.beanutils.PropertyUtils;
/**
* 相当于spring容器,用来保存bean
* @author yj.shi
*
*/
public class Container {
private static Map<String,Object> map=new HashMap<String,Object>();
public Container(){
Properties properties=new Properties();
InputStream in = null;
try {
in=Container.class.getClassLoader().getResourceAsStream("ioc.properties");
properties.load(in);
for(Map.Entry<Object, Object> entity:properties.entrySet()){
String key=entity.getKey().toString();
String value=entity.getValue().toString();
mappeingBean(key,value);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 对properties的内容进行映射
* @param key
* @param value
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws InvocationTargetException
*/
private void mappeingBean(String key,String value) throws InstantiationException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException{
String[] parts=key.split("\\.");
if(parts.length==1){//对象创建
map.put(parts[0],Class.forName(value).newInstance() );
}else{//注入引用关系
Object target=getBeanById(parts[0]);
Object resource=getBeanById(value);
PropertyUtils.setProperty(target, parts[1], resource);
}
}
/**
* 通过key过去spring容器中的数据
* @param key
* @return
*/
public static Object getBeanById(String key){
return map.get(key);
}
}
好了,最后就写一下测试方法
package com.springIoc.test;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import com.springIoc.container.Container;
import com.springIoc.service.ExcelServer;
public class TestMain {
@SuppressWarnings("static-access")
public static void main(String[] args) {
Container container=new Container();
Map<String,String[][]> map=reader(null);
for(String key:map.keySet()){
ExcelServer service=(ExcelServer) container.getBeanById(key);
service.save(map.get(key));
}
}
/**
* 将excel读入到Map
* key为sheet页名称,value为将exceld单元格解析成的二维数据
* @param file
* @return
*/
private static Map<String,String[][]> reader(File file){
Map<String,String[][]> map=new HashMap<String,String[][]>();
//可以根据sheet页名称作循环解析
map.put("excelService4CurrentMonth", null);
map.put("excelService4CNextMonth", null);
return map;
}
}
总结:springIoc的控制翻转,是角色的翻转,从我要主动找变为等待别人找我。找到我之后干什么,做的就是依赖注入,把我要的对象通过setter或者构造方法或者接口方式给我。这样既实现了类与类之间的解耦,又实现了依赖对象引用关系的建立。一举两得,轻松加愉快。
具体的实现就交给spring容器来做吧。