知识点:
批量导入(ocupload插件,pinyin4J
/POI解析Excel(apache POI)
/区域分页查询
/Combobox下拉框
/分区组合条件分页查询(ajax)
/分区数据导出(Excel下载)
BOS项目笔记第4天
1. 区域批量导入功能
*Ajax不支持文件上传。
*上传并且不刷新上传页面原理:
Target到一个0,0,0的隐藏iframe里,造成一个没有刷新的假象
<form target="myIframe" action="abc" method="post" enctype="multipart/form-data">
<input type="file" name="myFile">
<input type="submit" value="上传">
</form>
<iframe width="0" height="0" frameborder="0" name="myIframe"></iframe>
*选择上传文件后自动上传(无上传按钮)原理:
文件输入框onchange事件 内容一变化就自动提交
1.1 一键上传插件使用
将js文件复制到项目中
jquery.ocupload-1.1.2.js
ocupload jquery 的应用代码
$(function () {
$(".uploadfile").upload({
action: 'CourseXMLFileUploadHander.ashx',
name: 'xml',
params: {
'type': 'uploadCourseXMLFile',
'rand': Math.random()
},
onSelect: function (self, element) {
this.autoSubmit = false;
var re = new RegExp("(xml){1}quot;, "i");
if (!re.test(this.filename())) {
alert("Only xml file can be uploaded");
}
else {
this.submit();
}
},
onSubmit: function (self, element) {
$('.uploadfile').hide();
$('#ajax_update').parent().show();
//alert('Uploading file...');
},
onComplete: function (data, self, element) {
$('#ajax_update').parent().hide();
$('.uploadfile').show();
self.resetInput();
try {
var ret = data;
if (ret.indexOf("exception") >= 0) {
alert('Upload file exception: ' + eval(data)[0].exception);
}
else {
showSuccess('File is successfully Load.');
uploadSuccess(ret);
}
} catch (err) {
alert(data);
}
}
});
});
在需要使用一键上传插件的页面引入js文件,提供一个元素,调用插件的upload方法,动态修改html元素
简单示例
<body>
<input id="but1" type="button" value="上传">
<script type="text/javascript">
$("#but1").upload({
action : 'abc',//form表单提交地址
name : 'myFile'
});
</script>
</body>
原理:js插件会动态的创建form表单和iframe
1.1 在region.jsp页面应用一键上传插件
引入js文件
<script
src="${pageContext.request.contextPath }/js/jquery.ocupload-1.1.2.js"
type="text/javascript"></script>
调用插件的upload方法
$(function(){
$("#button-import").upload({
action:'${pageContext.request.contextPath}/regionAction_importXls.action',
name:'upload',
onComplete: function (data, self, element) {
if(data == '1'){
$.messager.alert("提示信息","导入数据成功!","info");
}else{
$.messager.alert("提示信息","导入数据失败!","warning");
}
}
});
});
1.2 创建RegionAction提供importXls方法
@Controller
@Scope("prototype")
public class RegionAction extends BaseAction<Region> {
private File upload;// 用于接收上传的文件
public void setUpload(File upload) {
this.upload = upload;
}
// 导入区域数据
public String importXls() throws FileNotFoundException, IOException {
System.out.println(upload);
// 加载Excel文件到内存中
HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(upload));
// 读取第一个Sheet页
HSSFSheet sheet = workbook.getSheetAt(0);
List<Region> list = new ArrayList<Region>();
for (Row row : sheet) {
// int rowNum = row.getRowNum();
String value1 = row.getCell(0).getStringCellValue();// id
String value2 = row.getCell(1).getStringCellValue();// provice
String value3 = row.getCell(2).getStringCellValue();// city
String value4 = row.getCell(3).getStringCellValue();// district
String value5 = row.getCell(4).getStringCellValue();// postcode
Region region = new Region(value1, value2, value3, value4, value5);
// 简码
String shortcode = StringUtils.join(
PinYin4jUtils.getHeadByString(value2 + value3), "");
// 城市编码
String citycode = PinYin4jUtils.hanziToPinyin(value3, "");
region.setShortcode(shortcode);
region.setCitycode(citycode);
list.add(region);
}
String f = "1";
try {
regionService.saveBatch(list);
} catch (Exception e) {
f = "0";
}
ServletActionContext.getResponse().setContentType(
"text/html;charset=UTF-8");
ServletActionContext.getResponse().getWriter().print(f);
return NONE;
}
配置struts.xml
略
*重复导入时出现主键冲突:
Duplicate entry ......
解决方法:使用saveOrUpdate
1.3 使用apache POI解析Excel文件
/**
* 测试POI解析Excel文件
*/
public class POITest {
@Test
public void test1() throws FileNotFoundException, IOException {
HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(new File(
"d:\\abc.xls")));
HSSFSheet sheet = workbook.getSheetAt(0);//读取第一个sheet页
for (Row row : sheet) {//循环读取每一行
String v1 = row.getCell(0).getStringCellValue();//获得当前行的第一个单元格的文字内容
String v2 = row.getCell(1).getStringCellValue();
String v3 = row.getCell(2).getStringCellValue();
String v4 = row.getCell(3).getStringCellValue();
String v5 = row.getCell(4).getStringCellValue();
System.out.println(v1 + " " + v2 + " " +v3 + " " + v4 + " " + v5);
}
}
}
Pinyin4J
@Test
public void test1() {
String city = "北京市";
String province = "河北省";
String city2 = "石家庄市";
String district = "长安区";
// 城市编码 北京市-----》beijing
String str1 = PinYin4jUtils.hanziToPinyin(
city.substring(0, city.length() - 1), "");
System.out.println(str1);
String info = province.substring(0, province.length() - 1)
+ city2.substring(0, city2.length() - 1)
+ district.substring(0, district.length() - 1);
// 简码河北省石家庄市长安区-----》hbsjzca
String[] strings = PinYin4jUtils.getHeadByString(info);
String join = StringUtils.join(strings, "");
System.out.println(join);
}
}
utils工具类
package cn.itcast.bos.utils;
import java.util.Arrays;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
public class PinYin4jUtils {
/**
* 将字符串转换成拼音数组
*
* @param src
* @return
*/
public static String[] stringToPinyin(String src) {
return stringToPinyin(src, false, null);
}
/**
* 将字符串转换成拼音数组
*
* @param src
* @return
*/
public static String[] stringToPinyin(String src, String separator) {
return stringToPinyin(src, true, separator);
}
/**
* 将字符串转换成拼音数组
*
* @param src
* @param isPolyphone
* 是否查出多音字的所有拼音
* @param separator
* 多音字拼音之间的分隔符
* @return
*/
public static String[] stringToPinyin(String src, boolean isPolyphone,
String separator) {
// 判断字符串是否为空
if ("".equals(src) || null == src) {
return null;
}
char[] srcChar = src.toCharArray();
int srcCount = srcChar.length;
String[] srcStr = new String[srcCount];
for (int i = 0; i < srcCount; i++) {
srcStr[i] = charToPinyin(srcChar[i], isPolyphone, separator);
}
return srcStr;
}
/**
* 将单个字符转换成拼音
*
* @param src
* @return
*/
public static String charToPinyin(char src, boolean isPolyphone,
String separator) {
// 创建汉语拼音处理类
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
// 输出设置,大小写,音标方式
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
StringBuffer tempPinying = new StringBuffer();
// 如果是中文
if (src > 128) {
try {
// 转换得出结果
String[] strs = PinyinHelper.toHanyuPinyinStringArray(src,
defaultFormat);
// 是否查出多音字,默认是查出多音字的第一个字符
if (isPolyphone && null != separator) {
for (int i = 0; i < strs.length; i++) {
tempPinying.append(strs[i]);
if (strs.length != (i + 1)) {
// 多音字之间用特殊符号间隔起来
tempPinying.append(separator);
}
}
} else {
tempPinying.append(strs[0]);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
tempPinying.append(src);
}
return tempPinying.toString();
}
public static String hanziToPinyin(String hanzi) {
return hanziToPinyin(hanzi, " ");
}
/**
* 将汉字转换成拼音
*
* @param hanzi
* @param separator
* @return
*/
public static String hanziToPinyin(String hanzi, String separator) {
// 创建汉语拼音处理类
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
// 输出设置,大小写,音标方式
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
String pinyingStr = "";
try {
pinyingStr = PinyinHelper.toHanyuPinyinString(hanzi, defaultFormat,
separator);
} catch (BadHanyuPinyinOutputFormatCombination e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pinyingStr;
}
/**
* 将字符串数组转换成字符串
*
* @param str
* @param separator
* 各个字符串之间的分隔符
* @return
*/
public static String stringArrayToString(String[] str, String separator) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < str.length; i++) {
sb.append(str[i]);
if (str.length != (i + 1)) {
sb.append(separator);
}
}
return sb.toString();
}
/**
* 简单的将各个字符数组之间连接起来
*
* @param str
* @return
*/
public static String stringArrayToString(String[] str) {
return stringArrayToString(str, "");
}
/**
* 将字符数组转换成字符串
*
* @param str
* @param separator
* 各个字符串之间的分隔符
* @return
*/
public static String charArrayToString(char[] ch, String separator) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < ch.length; i++) {
sb.append(ch[i]);
if (ch.length != (i + 1)) {
sb.append(separator);
}
}
return sb.toString();
}
/**
* 将字符数组转换成字符串
*
* @param str
* @return
*/
public static String charArrayToString(char[] ch) {
return charArrayToString(ch, " ");
}
/**
* 取汉字的首字母
*
* @param src
* @param isCapital
* 是否是大写
* @return
*/
public static char[] getHeadByChar(char src, boolean isCapital) {
// 如果不是汉字直接返回
if (src <= 128) {
return new char[] { src };
}
// 获取所有的拼音
String[] pinyingStr = PinyinHelper.toHanyuPinyinStringArray(src);
// 创建返回对象
int polyphoneSize = pinyingStr.length;
char[] headChars = new char[polyphoneSize];
int i = 0;
// 截取首字符
for (String s : pinyingStr) {
char headChar = s.charAt(0);
// 首字母是否大写,默认是小写
if (isCapital) {
headChars[i] = Character.toUpperCase(headChar);
} else {
headChars[i] = headChar;
}
i++;
}
return headChars;
}
/**
* 取汉字的首字母(默认是大写)
*
* @param src
* @return
*/
public static char[] getHeadByChar(char src) {
return getHeadByChar(src, true);
}
/**
* 查找字符串首字母
*
* @param src
* @return
*/
public static String[] getHeadByString(String src) {
return getHeadByString(src, true);
}
/**
* 查找字符串首字母
*
* @param src
* @param isCapital
* 是否大写
* @return
*/
public static String[] getHeadByString(String src, boolean isCapital) {
return getHeadByString(src, isCapital, null);
}
/**
* 查找字符串首字母
*
* @param src
* @param isCapital
* 是否大写
* @param separator
* 分隔符
* @return
*/
public static String[] getHeadByString(String src, boolean isCapital,
String separator) {
char[] chars = src.toCharArray();
String[] headString = new String[chars.length];
int i = 0;
for (char ch : chars) {
char[] chs = getHeadByChar(ch, isCapital);
StringBuffer sb = new StringBuffer();
if (null != separator) {
int j = 1;
for (char ch1 : chs) {
sb.append(ch1);
if (j != chs.length) {
sb.append(separator);
}
j++;
}
} else {
sb.append(chs[0]);
}
headString[i] = sb.toString();
i++;
}
return headString;
}
public static void main(String[] args) {
// pin4j 简码 和 城市编码
String s1 = "中华人民共和国";
String[] headArray = getHeadByString(s1); // 获得每个汉字拼音首字母
System.out.println(Arrays.toString(headArray));
String s2 ="长城" ;
System.out.println(Arrays.toString(stringToPinyin(s2,true,",")));
String s3 ="长";
System.out.println(Arrays.toString(stringToPinyin(s3,true,",")));
}
}
2. 区域分页查询
修改region.jsp页面中datagrid的url地址
在RegionAction中提供分页查询方法pageQuery
与上一天的代码重复需要提取到baseAction
3. 重构分页代码
在BaseAction中提取PageBean和DetachedCriteria对象
protected PageBean pageBean = new PageBean();
// 离线条件查询对象,用于包装查询条件
DetachedCriteria detachedCriteria = null;
在BaseAction中提供setPage和setRows方法
把分页ajax相应的两个参数row和page直接注入到上面提取的pageBean中
public void setPage(int page) {
pageBean.setCurrentPage(page);// 当前页码
}
public void setRows(int rows) {
pageBean.setPageSize(rows);// 每页显示记录数
}
在BaseAction的构造方法中创建离线条件查询对象,并且注入给PageBean
构造方法获取实体类型后创建离线查询条件对象并注入到pageBean中
public BaseAction() {
// 获得父类(BaseAction) 类型
ParameterizedType superclass = (ParameterizedType) this.getClass()
.getGenericSuperclass();
// 获得父类上的泛型数组
Type[] typeArguments = superclass.getActualTypeArguments();
// 获得实体类型
Class<T> domainClass = (Class<T>) typeArguments[0];
// 获得实体类型后创建离线条件查询对象
detachedCriteria = DetachedCriteria.forClass(domainClass);
pageBean.setDetachedCriteria(detachedCriteria);
try {
model = domainClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
在BaseAction中抽取方法writePageBean2Json和writeListBean2Json
/**
* 将PageBean序列化为json返回
*/
public void writePageBean2Json(PageBean pageBean, String[] excludes) {
// 使用jsonlib将PageBean对象序列化为json数据
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excludes);
String json = JSONObject.fromObject(pageBean, jsonConfig).toString();
ServletActionContext.getResponse().setContentType(
"text/json;charset=UTF-8");
try {
ServletActionContext.getResponse().getWriter().print(json);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 将List序列化为json返回
*/
public void writeListBean2Json(List list, String[] excludes) {
// 使用jsonlib将PageBean对象序列化为json数据
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excludes);
String json = JSONArray.fromObject(list, jsonConfig).toString();
ServletActionContext.getResponse().setContentType(
"text/json;charset=UTF-8");
try {
ServletActionContext.getResponse().getWriter().print(json);
} catch (IOException e) {
e.printStackTrace();
}
}
在RegionAction中的分页查询
分页查询代码简化为3条
/**
* 分页查询方法
* @throws IOException
*/
public String pageQuery() throws IOException{
regionService.pageQuery(pageBean);
this.writePageBean2Json(pageBean, new String[]{"currentPage","pageSize","detachedCriteria","subareas"});
return NONE;
}
4. 分区添加功能
4.1 Combobox下拉框使用
方式一:给静态的select标签应用
方式二:使用input标签通过url动态获取数据(json)
textField:为"option"下拉显示的内容
valueField::为最终提交的value值
<body>
<!-- 方式一 -->
<select class="easyui-combobox">
<option value="1">河北省石家庄市桥西区</option>
<option value="2">河北省石家庄市桥东区</option>
<option value="3">河北省石家庄市长安区</option>
</select>
<!-- 方式二 -->
<input
data-options="url:'${pageContext.request.contextPath }/json/data.json',
textField:'name',valueField:'id'"
type="text" class="easyui-combobox"/>
</body>
subarea分区页面的添加分区弹窗区域选择下拉框数据获取(模糊查询)
及添加分区功能
第一步:修改subarea.jsp页面中combobox的url地址
mode属性
定义了当文本改变时如何读取列表数据。设置为'remote'时,下拉列表框将会从服务器加载数据。
当设置为“remote”模式时,用户输入将被发送到名为'q'的HTTP请求参数到服务器检索新数据。
<td>
<input class="easyui-combobox" name="region.id"
data-options="mode:'remote',valueField:'id',textField:'name',
url:'${pageContext.request.contextPath }/regionAction_list.action'" />
</td>
对应分区类也应增加与下拉栏textField对应的name属性(省市区)
private String id;//编号
private String province;//省
private String city;//市
private String district;//区
private String postcode;//邮编
private String shortcode;//简码
private String citycode;//城市编码
private Set subareas = new HashSet(0);//区域对应的多个分区
public String getName(){
return province + city + district;
}
第二步:在RegionAction中提供list方法查询区域数据
private String q;//模糊查询参数
public void setQ(String q) {
this.q = q;
}
/**
* 查询所有区域返回json
*/
public String list(){
List<Region> list = null;
if(StringUtils.isNotBlank(q)){
//根据q进行模糊查询
list = regionService.findByQ(q.trim());
}else{
//查询所有
list = regionService.findAll();
}
String[] excludes = new String[]{"subareas"};
this.writeListBean2Json(list, excludes);
return NONE;
}
Service中:
@Override
public List<Region> findByQ(String q) {
return regionDao.findByNameQuery("findByQ","%"+q+"%","%"+q+"%","%"+q+"%");
}
baseIDaompl命名查询
@Override
public List<T> findByNameQuery(String hqlName, Object... params) {
List findByNamedQuery = this.getHibernateTemplate().findByNamedQuery(hqlName,params);
return findByNamedQuery;
}
对应*hbm.xml提供query hql语句
注意:命名查询配置语句中不能出现双引号" "会报错,因为语句是按字符串来提取的,xml配置+" "来拼接也不行
<query name="findByQ">
FROM Region WHERE city LIKE ? OR province LIKE ? OR district LIKE ?
</query>
第三步:为保存按钮绑定事件
<a id="save" icon="icon-save" href="#" class="easyui-linkbutton" plain="true" >保存</a>
<script type="text/javascript">
$(function(){
//为保存按钮绑定事件
$("#save").click(function(){
var v = $("#addForm").form("validate");
if(v){
$("#addForm").submit();
}
});
});
</script><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
第四步:创建一个SubareaAction,提供add方法用于添加分区
略
5. 分区组合条件分页查询
基于datagrid的load方法实现组合条件分页查询
*带关联查询的分页查询转换json会出错
freemarker.template.TemplateModelException:
Method public java.lang.Stringorg.apache.commons.lang.exception
.NestableRuntimeException.getMessage(int)threw an exception when invoked on net.sf.json.JSONException:
java.lang.reflect.InvocationTargetException
原因:关联对象延迟加载是代理对象无法转换成json数据
解决: 修改对应需关联对象hbm,xml文件的lazy属性为false 解决关联查询问题
<many-to-one name="region" class="cn.feibai.bos.domain.Region" fetch="select" lazy="false">
<column name="region_id" length="32" />
</many-to-one>
第一步:提供组合条件查询窗口
第二步:提供一个工具方法,将form表单中的输入项转为json数据,提交参数
$.fn.serializeJson=function(){
var serializeObj={};
var array=this.serializeArray();
$(array).each(function(){
if(serializeObj[this.name]){
if($.isArray(serializeObj[this.name])){
serializeObj[this.name].push(this.value);
}else{
serializeObj[this.name]=[serializeObj[this.name],this.value];
}
}else{
serializeObj[this.name]=this.value;
}
});
return serializeObj;
};
第三步:为查询按钮绑定事件,调用datagrid的load方法,重写发起ajax请求,提交参数
目的:这样发起的查询是ajax请求,条件参数会缓存在页面.
ajax没有全部刷新页面所以对应分页查询的条件也不会丢失
方法:load
参数:param
详情:
加载和显示第一页的所有行。如果指定了'param',它将取代'queryParams'属性。通常可以通过传递一些参数执行一次查询,通过调用这个方法从服务器加载新数据。
<!-- 查询分区 -->
<script type="text/javascript">
//为查询按钮绑定事件
$(function(){
$.fn.serializeJson=function(){
var serializeObj={};
var array=this.serializeArray();
$(array).each(function(){
if(serializeObj[this.name]){
if($.isArray(serializeObj[this.name])){
serializeObj[this.name].push(this.value);
}else{
serializeObj[this.name]=[serializeObj[this.name],this.value];
}
}else{
serializeObj[this.name]=this.value;
}
});
return serializeObj;
};
$("#btn").click(function(){
//获取查询条件---一次获取所有的查询条件,将查询条件封装成json数据
var params = $("#searchForm").serializeJson();
//重新发起一次ajax请求,提交参数
$("#grid").datagrid("load",params);
//关闭查询窗口
$("#searchWindow").window("close");
});
});
</script>
第四步:改造SubareaAction中的pageQuery方法,加入组合条件分页查询逻辑
Restrictions API
/**
* 分页组合条件查询
*/
public String pageQuery() {
DetachedCriteria subareaDC = pageBean.getDetachedCriteria();
// 从模型对象中获取提交的查询参数
String addresskey = model.getAddresskey();// 关键字
// 单表查询
if (StringUtils.isNotBlank(addresskey)) {
// 添加查询条件,根据关键字进行模糊查询
subareaDC.add(Restrictions.like("addresskey",
"%" + addresskey.trim() + "%"));
}
Region region = model.getRegion();
// 多表查询
if (region != null) {
String province = region.getProvince();
String city = region.getCity();
String district = region.getDistrict();
DetachedCriteria regionDC = subareaDC.createCriteria("region");
if (StringUtils.isNotBlank(province)) {
// 添加查询条件,根据省进行模糊查询
regionDC.add(Restrictions
.like("province", "%" + province + "%"));
}
if (StringUtils.isNotBlank(city)) {
// 添加查询条件,根据省进行模糊查询
regionDC.add(Restrictions.like("city", "%" + city + "%"));
}
if (StringUtils.isNotBlank(district)) {
// 添加查询条件,根据省进行模糊查询
regionDC.add(Restrictions
.like("district", "%" + district + "%"));
}
}
subareaService.pageQuery(pageBean);
String[] excludes = new String[] { "decidedzone", "subareas" };
this.writePageBean2Json(pageBean, excludes);
return NONE;
}
6. 分区数据导出功能(Excel提供下载)
第一步:修改subarea.jsp页面中导出按钮的事件
function doExport(){
//发起请求Action,查询所有分区数据,写到Excel文件中并提供下载
window.location.href = "${pageContext.request.contextPath}/subareaAction_exportXls.action";
}
第二步:在Action中提供exportXls方法
两种方法:
方式一:原始手动设置响应下载
文件名乱码工具类
import java.io.IOException;
import java.net.URLEncoder;
import sun.misc.BASE64Encoder;
public class FileUtils {
/**
* 下载文件时,针对不同浏览器,进行附件名的编码
*
* @param filename
* 下载文件名
* @param agent
* 客户端浏览器
* @return 编码后的下载附件名
* @throws IOException
*/
public static String encodeDownloadFilename(String filename, String agent)
throws IOException {
if (agent.contains("Firefox")) { // 火狐浏览器
filename = "=?UTF-8?B?"
+ new BASE64Encoder().encode(filename.getBytes("utf-8"))
+ "?=";
filename = filename.replaceAll("\r\n", "");
} else { // IE及其他浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+"," ");
}
return filename;
}
}
/**
* 导出分区数据到Excel文件并提供下载
*
* @throws IOException
*/
public String exportXls() throws IOException {
List<Subarea> list = subareaService.findAll();
// 使用POI将查询的数据写入Excel文件中
HSSFWorkbook workbook = new HSSFWorkbook();
// 在工作表中创建一个sheet页
HSSFSheet sheet = workbook.createSheet("分区数据");
// 创建标题行
HSSFRow headRow = sheet.createRow(0);
// 创建单元格
headRow.createCell(0).setCellValue("分区编号");
headRow.createCell(1).setCellValue("关键字");
headRow.createCell(2).setCellValue("地址");
headRow.createCell(3).setCellValue("省市区");
for (Subarea subarea : list) {
// 创建数据行
HSSFRow dataRow = sheet.createRow(sheet.getLastRowNum() + 1);
String id = subarea.getId();
String addresskey = subarea.getAddresskey();
String position = subarea.getPosition();
Region region = subarea.getRegion();
dataRow.createCell(0).setCellValue(id);
dataRow.createCell(1).setCellValue(addresskey);
dataRow.createCell(2).setCellValue(position);
if (region != null) {
String province = region.getProvince();
String city = region.getCity();
String district = region.getDistrict();
String info = province + city + district;
dataRow.createCell(3).setCellValue(info);
}
}
String filename = "分区数据.xls";
String agent = ServletActionContext.getRequest().getHeader("user-agent");//浏览器类型
filename = FileUtils.encodeDownloadFilename(filename, agent );
//根据文件名称动态获得类型
String contentType = ServletActionContext.getServletContext()
.getMimeType(filename);
// 通知客户端下载文件的类型
ServletActionContext.getResponse().setContentType(contentType);
//指定以附件形式下载,指定文件名称
ServletActionContext.getResponse().setHeader("content-disposition", "attachment;filename=" + filename);
// 通过输出流向客户端浏览器写Excel文件
ServletOutputStream out = ServletActionContext.getResponse().getOutputStream();
workbook.write(out);
return NONE;
}
}
方式二:通过struts2的stream结果集下载
思路百度自博客(http://xiaowei-qi-epro-com-cn.iteye.com/blog/2030671):
思路是,先创建一个输出流,将这个excel写入到输出流里面,然后再通过这个输出流来得到我们所需要的输入流.
使用了ByteArrayOutputStream和ByteArrayInputStream类...处理的思想是,将HSSFWorkbook 写入ByteArrayOutputStream.然后用ByteArrayOutputStream来转换为字节流..然后再将字节流转换为ByteArrayInputStream ..至此,我们就在内存中将excel转换成了输入流
<pre name="code" class="java"> private InputStream target;
public InputStream getTarget() {
return target;
}
//下载文件名,存在中文乱码
private String downloadFileName;
public String getDownloadFileName() throws UnsupportedEncodingException {
// 处理中文乱码
if(downloadFileName != null){
return new String(downloadFileName.getBytes("GBK"),"ISO-8859-1");
}
return downloadFileName;
}
/**
* 下载所有分区信息以xls格式
* @return
* @throws IOException
*/
public String export() throws IOException{
List<Subarea> list=subareaService.findAll();
//把list写入excel文档
HSSFWorkbook book=new HSSFWorkbook();
HSSFSheet sheet = book.createSheet("全部分区详情");
//创建初始标题行
HSSFRow row = sheet.createRow(0);
row.createCell(0).setCellValue("分拣编号");
row.createCell(1).setCellValue("省市区");
row.createCell(2).setCellValue("关键字");
row.createCell(3).setCellValue("位置");
//遍历list
for (Subarea subarea : list) {
HSSFRow createRow = sheet.createRow(sheet.getLastRowNum()+1);
String id = subarea.getId();
String nameInfo = subarea.getRegion().getName();
String addresskey = subarea.getAddresskey();
String position = subarea.getPosition();
createRow.createCell(0).setCellValue(id);
createRow.createCell(1).setCellValue(nameInfo);
createRow.createCell(2).setCellValue(addresskey);
createRow.createCell(3).setCellValue(position);
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
book.write(out);
target = new ByteArrayInputStream(out.toByteArray());
out.close();
downloadFileName="分区详情.xls";
return "download";
}
配置文件
<!-- 分区 -->
<action name="subareaAction_*" class="subareaAction" method="{1}">
<result name="subareaList">/WEB-INF/pages/base/subarea.jsp</result>
<result name="download" type="stream">
<!-- 设置响应头 -->
<param name="contentDisposition">attachment;filename=${downloadFileName}</param>
<!-- 确定流 -->
<param name="inputName">target</param>
</result>
</action>