您的位置:首页 > 其它

使用模板设计模式解决问题

2018-01-16 16:14 369 查看
最近,在做一个系统,这个系统有部分数据是用户通过CSV文件进行导入的,我并不是很常操作这个,在网上搜索到一个操作CSV的文件类,很简单,具体的操作请看连接

http://blog.csdn.net/loongshawn/article/details/53423121

然后是在后台开始编代码,由于所上传的数据一定是保存到数据库的,所以我设计了这么一个类

     package com.cyberway.watsons.business.store.abstractf;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import org.hibernate.AssertionFailure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.csvreader.CsvReader;
import com.cyberway.watsons.common.service.HibernateManager;

/**
* @author while(true){study}
* @date 2018年1月16日 下午1:39:58
* @Description 有些文件是来源于CSV中的,EXCEL那个就暂时不需要了..
* @version V1.0
*/
@SuppressWarnings("all")
public abstract class DataFromCSV<T> {

public static final DateFormat DATE_FORMAT_LINE = new SimpleDateFormat("yyyy-MM-dd");
public static final DateFormat DATE_FORMAT_SPRIT = new SimpleDateFormat("yyyy/MM/dd");

private static final Logger LOGGER = LoggerFactory.getLogger(DataFromCSV.class);

/**
* 发生异常时的回调方法,默认只把异常信息打印出来了,可以根据自己的需要覆盖然后进行相应的处理
* @param e 抓取到的异常信息
* @param records 当行的数据
* @param dataService 所对应数据的service服务层
*/
protected void errorCall(Exception e, String [] records, HibernateManager<T> dataService) {
e.printStackTrace();
}

/**
* 模板设计模式:子类只需要拿到 records 进行处理返回一个要保存的对象即可
* @param records
* @return 返回子类想处理的对象出来
*/
public abstract Object getObject(String [] records);

/**
*
* @param inputStream 传入的CSV表格流每列的第一个单元格的值一定要是 keyCode,要不然会有问题!
* @param dataService 这里不需要传入泛型,要不然调用的时候需要确定这个类型,没办法发过来,其他地方可以用泛型
*/
public void saveData(InputStream inputStream, HibernateManager dataService) {
CsvReader csvReader = getReaderNotHeads(inputStream);
try {
String [] records =null;
while(csvReader.readRecord()) {
try {
String currentRecord = csvReader.getRawRecord();
//防止用户输完删掉的数据还进来循环
if(currentRecord.startsWith(",")) {
continue;
}
records = currentRecord.split(",");
Object object = getObject(records);
if(object != null) {
dataService.saveOrUpdate(object);
}
} catch(Exception e) {
if(e.getClass() == AssertionFailure.class) {
LOGGER.error("该数据重复了,不允许再保存!!" + Arrays.asList(records));
}
errorCall(e, records, dataService);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeResoure(inputStream, csvReader);
}
}

/**
* 获取一个CsvReader 类准备操作下面的数据,并且已经把表头过滤了
* @param inputStream
* @return
*/
protected CsvReader getReaderNotHeads(InputStream inputStream) {
CsvReader csvReader = getReader(inputStream);
try {
csvReader.readHeaders();
} catch (IOException e) {
e.printStackTrace();
}
return csvReader;
}

/**
* 获取一个CsvReader 类准备操作下面的数据,没有过滤表头
* @param inputStream
* @return
*/
protected CsvReader getReader(InputStream inputStream) {
CsvReader csvReader = new CsvReader(inputStream, ',', Charset.forName("GBK"));
return csvReader;
}

/**
* 关闭所有打开流的一个方法
* @param inputStream
* @param csvReader
*/
protected void closeResoure(InputStream inputStream, CsvReader csvReader) {
try {
if(inputStream != null) inputStream.close();
if(csvReader != null) csvReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 时间格式跟用户本地设置有关,所以需要自己再去解析这个东西
* @param dateStr
* @return
* @throws ParseException
*/
protected Date parseDate(String dateStr){
try {
if(dateStr.contains("/")) return DATE_FORMAT_SPRIT.parse(dateStr);
if(dateStr.contains("-")) return DATE_FORMAT_LINE.parse(dateStr);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}


     刚开始我是把saveData 弄为抽象方法了,后来发现如果有其他地方也需要用到上传CSV文件,其实都是一样的,需要打开

    那个流,不一样的只是保存到数据库的对象不一样,所以后来封装成这样了,以后拓展时就会看到效果

    这是其中一个实现类

    package com.cyberway.watsons.business.store.abstractf.impl;

import java.util.Date;

import org.hibernate.AssertionFailure;
import org.springframework.beans.BeanUtils;

import com.cyberway.watsons.business.store.abstractf.DataFromCSV;
import com.cyberway.watsons.business.store.activity.model.ActivityProject;
import com.cyberway.watsons.common.model.CriteriaVo;
import com.cyberway.watsons.common.service.HibernateManager;
/**
* @author while(true){study}
* @date 2018年1月15日 上午10:00:43
* @Description ActivityProject 的数据就是来源一个CSV表格
* @version V1.0
*/
public class ActivityProjectData extends DataFromCSV<ActivityProject>{

/**
* 这里使用了模板设计模式,只需要覆盖父类这个方法处理对象返回给父类调用即可
*/
@Override
public Object getObject(String[] records) {
ActivityProject project = new ActivityProject();
//组装一个所需要的对象并进行保存到数据库中
project.setKeyCode(records[0]);
project.setProvince(records[1]);
project.setCity(records[2]);
project.setStoreId(records[3]);
project.setStoreName(records[4]);
project.setStoreAddr(records[5]);
project.setProjectName(records[6]);
String date = records[7];
//因为CSV的日期格式无法通过设置单元格格式来配置,每次重新打开就失效了,所以直接从后台配置成只支持这种 2018-2-13 格式的数据
if(date.contains("/")) {
date = date.replaceAll("/", "-");
}
project.setProjectDate(super.parseDate(date));
project.setProjectPeriod(records[8]);
project.setCount(Integer.parseInt(records[9]));
project.setUpdated(new Date());
return project;
}

@Override
protected void errorCall(Exception e, String[] records, HibernateManager<ActivityProject> dataService) {
//重复数据插入异常回调处理
if(e.getClass() == AssertionFailure.class) {
updateProject((ActivityProject) getObject(records), dataService);
} else {
super.errorCall(e, records, dataService);
}
}

/**
* 更新该对象
* @param project
* @param dataService
* @return
*/
private void updateProject(ActivityProject project, HibernateManager<ActivityProject> dataService) {
String criteriaType = CriteriaVo.TYPE_EQ;
CriteriaVo[] criteriaVos = new CriteriaVo[4];
criteriaVos[0] = new CriteriaVo("keyCode", project.getKeyCode(), criteriaType);
criteriaVos[1] = new CriteriaVo("storeId", project.getStoreId(), criteriaType);
criteriaVos[2] = new CriteriaVo("projectName", project.getProjectName(), criteriaType);
criteriaVos[3] = new CriteriaVo("projectPeriod", project.getProjectPeriod(), criteriaType);
ActivityProject dbProject = dataService.getByCriteriaVo(ActivityProject.class, criteriaVos);
if(dbProject != null) {
BeanUtils.copyProperties(project, dbProject, new String[]{"id"});
dataService.saveOrUpdate(dbProject);
}
}
}


   

    使用的时候就简单了

    

/**
* 根据用户所给的一个CSV文件进行处理放到数据库中
* @param projectData
* @return
*/
@ResponseBody
@RequestMapping("/upload/data")
public Map<String, String> saveDataWithCsv(@RequestParam("projectData") MultipartFile projectData) {
Map<String, String> result = new HashMap<>();
result.put("message", "success");
try {
new ActivityProjectData().saveData(projectData.getInputStream(), activityProjectService);
} catch (Exception e) {
result.put("message", "服务器内部出现错误");
e.printStackTrace();
}
return result;
}
     只需要把流对象和对应的数据库操作业务层传过去即可,所有业务层都要继承  HibernateManager

 

    模板设计模式可以参考这个连接

    https://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html

    

     最后就是上传文件到后台处理了,总的来说注意两点,1是提交的form表达的编码格式要换为

     enctype="multipart/form-data" 

<form action="/activity/project/upload/data"  method="post" enctype="multipart/form-data">

    2,我用的是ajax与后台交互的,用jQuery搞了好久一直报错,后来用了 ajaxFileUpload 这个组件去弄一下就好了

   所以还是用组件吧,基本使用方法可以看下

https://www.cnblogs.com/kissdodog/archive/2012/12/15/2819025.html

   需要注意的是使用 ajaxFileUpload  组件进行操作,好像返回json数据有问题,估计是源码里面的问题

   所以直接返回一个string类型回去吧,然后自己再解析一下好了,要不然你得去改源码....好像以前就遇过这个问题了..

文章到这里就结束了,可以总到的是设计模式的应用,以及某些工具类的使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐