1、前端页面逻辑
首先ajax不能做文件上传。需要用到jquery插件。
第一步:在jsp页面中引入插件的js文件
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery.ocupload-1.1.2.js"></script>
第二步:在页面中提供一个元素以供标示。
{ id : 'button-import', text : '导入', iconCls : 'icon-redo' }
第三步:调用插件提供的upload方法,动态修改页面html代码
//调用OCupload插件的方法
$("#button-import").upload({
action: '${pageContext.request.contextPath}/regionAction_importXls.action',
name: 'myFile',
onComplete: function(data) {
if(data == '1'){
//上传成功
$.messager.alert("提示信息","区域数据导入成功!","info");
}else{
//失败
$.messager.alert("提示信息","区域数据导入失败!","warning");
}
}
});
2、后台系统逻辑
pojo基础类:Region
package com.crm.bos.domain;
import java.util.HashSet;
import java.util.Set;
/** * 区域实体 * */
public class Region implements java.io.Serializable {
// Fields
private String id;
private String province;
private String city;
private String district;
private String postcode;
private String shortcode;
private String citycode;
public String getName(){
return province+city + district;
}
private Set subareas = new HashSet(0);
// Constructors
/** default constructor */
public Region() {
}
/** minimal constructor */
public Region(String id) {
this.id = id;
}
/** full constructor */
public Region(String id, String province, String city, String district,
String postcode, String shortcode, String citycode, Set subareas) {
this.id = id;
this.province = province;
this.city = city;
this.district = district;
this.postcode = postcode;
this.shortcode = shortcode;
this.citycode = citycode;
this.subareas = subareas;
}
// Property accessors
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getProvince() {
return this.province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return this.city;
}
public void setCity(String city) {
this.city = city;
}
public String getDistrict() {
return this.district;
}
public void setDistrict(String district) {
this.district = district;
}
public String getPostcode() {
return this.postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
public String getShortcode() {
return this.shortcode;
}
public void setShortcode(String shortcode) {
this.shortcode = shortcode;
}
public String getCitycode() {
return this.citycode;
}
public void setCitycode(String citycode) {
this.citycode = citycode;
}
public Set getSubareas() {
return this.subareas;
}
public void setSubareas(Set subareas) {
this.subareas = subareas;
}
}
相应的Hibernate映射文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.crm.bos.domain.Region" table="bc_region" catalog="bos19">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="assigned" />
</id>
<property name="province" type="java.lang.String">
<column name="province" length="50" />
</property>
<property name="city" type="java.lang.String">
<column name="city" length="50" />
</property>
<property name="district" type="java.lang.String">
<column name="district" length="50" />
</property>
<property name="postcode" type="java.lang.String">
<column name="postcode" length="50" />
</property>
<property name="shortcode" type="java.lang.String">
<column name="shortcode" length="30" />
</property>
<property name="citycode" type="java.lang.String">
<column name="citycode" length="30" />
</property>
<set name="subareas" inverse="true">
<key>
<column name="region_id" length="32" />
</key>
<one-to-many class="com.crm.bos.domain.Subarea" />
</set>
</class>
</hibernate-mapping>
action处理类:
@Controller
@Scope("prototype")
public class RegionAction extends BaseAction<Region> {
// 接收上传的文件
private File myFile;
public void setMyFile(File myFile) {
this.myFile = myFile;
}
/** * 批量导入 * * @throws IOException * @throws FileNotFoundException */
public String importXls() throws Exception {
String flag = "1";
// 使用POI解析Excel文件
try {
HSSFWorkbook workbook = new HSSFWorkbook(
new FileInputStream(myFile));
// 获得第一个sheet页
HSSFSheet sheet = workbook.getSheetAt(0);
List<Region> list = new ArrayList<Region>();
for (Row row : sheet) {
int rowNum = row.getRowNum();
if (rowNum == 0) {
// 第一行,标题行,忽略
continue;
}
String id = row.getCell(0).getStringCellValue();
String province = row.getCell(1).getStringCellValue();
String city = row.getCell(2).getStringCellValue();
String district = row.getCell(3).getStringCellValue();
String postcode = String.valueOf((long) row.getCell(4)
.getNumericCellValue());
Region region = new Region(id, province, city, district,
postcode, null, null, null);
city = city.substring(0, city.length() - 1);
String[] stringToPinyin = PinYin4jUtils.stringToPinyin(city);
String citycode = StringUtils.join(stringToPinyin, "");
// 简码---->>HBSJZCA
province = province.substring(0, province.length() - 1);
district = district.substring(0, district.length() - 1);
String info = province + city + district;// 河北石家庄长安
String[] headByString = PinYin4jUtils.getHeadByString(info);
String shortcode = StringUtils.join(headByString, "");
region.setCitycode(citycode);
region.setShortcode(shortcode);
list.add(region);
}
regionService.saveBatch(list);
} catch (Exception e) {
e.printStackTrace();
flag = "0";
}
ServletActionContext.getResponse().setContentType(
"text/html;charset=UTF-8");
ServletActionContext.getResponse().getWriter().print(flag);
return NONE;
}
这里使用Pinyin4J生成简码和城市编码
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,",")));
}
}
service层代码如下:
@Service
@Transactional
public class RegionServiceImpl implements IRegionService{
@Resource
private IRegionDao regionDao;
public void saveBatch(List<Region> list) {
for (Region region : list) {
regionDao.saveOrUpdate(region);
}
}
1、前端逻辑
function doDblClickRow(rowIndex, rowData){
//rowIndex是选中的行号索引(从0开始),rowData是当前行的数据,json格式
//弹出修改窗口
$('#addRegionWindow').window("open");
$("#addRegionForm").form("load",rowData);//载入原有的表单数据
}
2、后台逻辑
action类:
//添加和修改功能
public String add(){
regionService.save(model);
return "list";
}
service层:
public void save(Region model) {
regionDao.saveOrUpdate(model);
}
1、前端逻辑
function doDelete(){
//判断是否选择了内容
var rows = $("#grid").datagrid("getSelections");
if(rows.length==0){
//未选中内容
$.messager.alert("提示信息","请选择需要删除的数据","warning");
}else{
//获得选中的区域id,拼接字符串
var array = new Array();
for(var i=0;i<rows.length;i++){
var id=rows[i].id;
array.push(id);
}
var ids = array.join(",");//将数组中的数据分割
//发送请求
window.location.href="${pageContext.request.contextPath }/regionAction_delete.action?ids="+ids;
}
}
2、后台逻辑
action类:
// 批量作废
private String ids;
public String delete() {
regionService.deleteBatch(ids);
System.out.println();
return "list";
}
public void setIds(String ids) {
this.ids = ids;
}
service层:
public void deleteBatch(String ids) {
String[] sids = ids.split(",");
Region region=null;
for (String id : sids) {
region=new Region(id);
regionDao.delete(region);
}
}
1、在BaseAction中抽取PageBean对象和条件查询对象
protected PageBean pageBean = new PageBean();
DetachedCriteria detachedCriteria = null;//条件查询对象
protected int page;// 分页参数
protected int rows;
2、在BaseAction中提供setPage和setRows方法
public void setPage(int page) {
pageBean.setCurrentPage(page);
}
public void setRows(int rows) {
pageBean.setPageSize(rows);
}
3、在BaseAction的构造方法中创建条件查询对象,并注入给PageBean对象
public BaseAction() {
ParameterizedType genericSuperclass = null;
Type genericSuperclass2 = this.getClass().getGenericSuperclass();
if(genericSuperclass2 instanceof ParameterizedType){
genericSuperclass=(ParameterizedType) genericSuperclass2;
}else {//此时this为shiro的代理对象
genericSuperclass=(ParameterizedType) this.getClass().getSuperclass().getGenericSuperclass();
}
Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
Class<T> entityClass = (Class<T>) actualTypeArguments[0];
detachedCriteria = DetachedCriteria.forClass(entityClass);
pageBean.setDetachedCriteria(detachedCriteria);
try {
model = entityClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
4、在BaseAction中抽取将PageBean对象转为json的方法
// 将pageBean对象转为json
public void writePageBean2Json(PageBean pageBean, String[] excludes) {
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excludes);
JSONObject jsonObject = JSONObject.fromObject(pageBean, jsonConfig);
String json = jsonObject.toString();
ServletActionContext.getResponse().setContentType(
"text/json;charset=UTF-8");
try {
ServletActionContext.getResponse().getWriter().print(json);
} catch (IOException e) {
e.printStackTrace();
}
}
1、前端页面逻辑
<!-- 添加 修改分区 -->
<div class="easyui-window" title="分区添加修改" id="addSubareaWindow" collapsible="false" minimizable="false" maximizable="false" style="top:20px;left:200px">
<div style="height:31px;overflow:hidden;" split="false" border="false" >
<div class="datagrid-toolbar">
<a id="save" icon="icon-save" href="#" class="easyui-linkbutton" plain="true" >保存</a>
<script type="text/javascript"> $(function(){ $("#save").click(function(){ var v = $("#addSubareaForm").form("validate"); if(v){ $("#addSubareaForm").submit(); } }); }); </script>
</div>
</div>
<div style="overflow:auto;padding:5px;" border="false">
<form id="addSubareaForm" action="${pageContext.request.contextPath }/subareaAction_add.action" method="post">
<table class="table-edit" width="80%" align="center">
<tr class="title">
<td colspan="2">分区信息</td>
</tr>
<tr>
<td>选择区域</td>
<td>
<input class="easyui-combobox" name="region.id" data-options="mode:'remote',valueField:'id',textField:'name',url:'${pageContext.request.contextPath }/regionAction_listajax.action'" />
</td>
</tr>
<tr>
<td>关键字</td>
<td><input type="text" name="addresskey" class="easyui-validatebox" required="true"/></td>
</tr>
<tr>
<td>起始号</td>
<td><input type="text" name="startnum" class="easyui-validatebox" required="true"/></td>
</tr>
<tr>
<td>终止号</td>
<td><input type="text" name="endnum" class="easyui-validatebox" required="true"/></td>
</tr>
<tr>
<td>单双号</td>
<td>
<select class="easyui-combobox" name="single" style="width:150px;">
<option value="0">单双号</option>
<option value="1">单号</option>
<option value="2">双号</option>
</select>
</td>
</tr>
<tr>
<td>位置信息</td>
<td><input type="text" name="position" class="easyui-validatebox" required="true" style="width:250px;"/></td>
</tr>
</table>
</form>
</div>
</div>
2、在RegionAction中提供listajax方法,查询所有的区域数据,返回json数据。
基础pojo类如下:
package com.crm.bos.domain;
/** * 分区实体 * */
public class Subarea implements java.io.Serializable {
// Fields
private String id;
private Decidedzone decidedzone;
private Region region;
private String addresskey;
private String startnum;
private String endnum;
private String single;
private String position;
public String getSubareaid(){
return id;
}
// Constructors
/** default constructor */
public Subarea() {
}
/** minimal constructor */
public Subarea(String id) {
this.id = id;
}
/** full constructor */
public Subarea(String id, Decidedzone decidedzone, Region region,
String addresskey, String startnum, String endnum, String single,
String position) {
this.id = id;
this.decidedzone = decidedzone;
this.region = region;
this.addresskey = addresskey;
this.startnum = startnum;
this.endnum = endnum;
this.single = single;
this.position = position;
}
// Property accessors
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public Decidedzone getDecidedzone() {
return this.decidedzone;
}
public void setDecidedzone(Decidedzone decidedzone) {
this.decidedzone = decidedzone;
}
public Region getRegion() {
return this.region;
}
public void setRegion(Region region) {
this.region = region;
}
public String getAddresskey() {
return this.addresskey;
}
public void setAddresskey(String addresskey) {
this.addresskey = addresskey;
}
public String getStartnum() {
return this.startnum;
}
public void setStartnum(String startnum) {
this.startnum = startnum;
}
public String getEndnum() {
return this.endnum;
}
public void setEndnum(String endnum) {
this.endnum = endnum;
}
public String getSingle() {
return this.single;
}
public void setSingle(String single) {
this.single = single;
}
public String getPosition() {
return this.position;
}
public void setPosition(String position) {
this.position = position;
}
}
对应的Hibernate映射文件如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.crm.bos.domain.Subarea" table="bc_subarea" catalog="bos19">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid" />
</id>
<many-to-one name="decidedzone" class="com.crm.bos.domain.Decidedzone" fetch="select">
<column name="decidedzone_id" length="32" />
</many-to-one>
<many-to-one lazy="false" name="region" class="com.crm.bos.domain.Region" fetch="select">
<column name="region_id" length="32" />
</many-to-one>
<property name="addresskey" type="java.lang.String">
<column name="addresskey" length="100" />
</property>
<property name="startnum" type="java.lang.String">
<column name="startnum" length="30" />
</property>
<property name="endnum" type="java.lang.String">
<column name="endnum" length="30" />
</property>
<property name="single" type="java.lang.String">
<column name="single" length="1" />
</property>
<property name="position" type="java.lang.String">
<column name="position" />
</property>
</class>
</hibernate-mapping>
action类:
// 查询所有区域数据,返回json,支持模糊查询
public String listajax() throws IOException{
List<Region> list = null;//regionService.findAll();
if(StringUtils.isNotBlank(q)){
list = regionService.findByQ(q.trim());
}else{
list = regionService.findAll();
}
String[] excludes = new String[]{"subareas","province","city","district","postcode","shortcode","citycode"};
this.writeList2Json(list, excludes);
return NONE;
}
为了使返回的json中含有name字段,需要在Region类中提供getName方法
1、为查询按钮绑定事件,调用datagrid的load方法,重新发起ajax请求,并且输入框提交参数
$("#btn").click(function(){
//工具方法,可以将指定的表单中的输入项目序列号为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;
};
var params = $("#searchForm").serializeJson();
//重新发起一次ajax的请求
$("#grid").datagrid("load",params);
//关闭查询窗口
$('#searchWindow').window("close");
});
2、修改SubareaAction中的分页查询方法,封装分页查询的条件
public String pageQuery() throws Exception{
//在查询之前,封装条件
DetachedCriteria detachedCriteria2 = pageBean.getDetachedCriteria();
String addresskey = model.getAddresskey();
Region region = model.getRegion();
if(StringUtils.isNotBlank(addresskey)){
//按照地址关键字模糊查询
detachedCriteria2.add(Restrictions.like("addressKey", addresskey));
}
if(region != null){
//创建别名,用于多表关联查询
detachedCriteria2.createAlias("region", "r");
String province = region.getProvince();
String city = region.getCity();
String district = region.getDistrict();
if(StringUtils.isNotBlank(province)){
//按照省进行模糊查询
detachedCriteria2.add(Restrictions.like("r.province", "%"+province+"%"));
}
if(StringUtils.isNotBlank(city)){
//按照省进行模糊查询
detachedCriteria2.add(Restrictions.like("r.city", "%"+city+"%"));
}
if(StringUtils.isNotBlank(district)){
//按照省进行模糊查询
detachedCriteria2.add(Restrictions.like("r.district", "%"+district+"%"));
}
}
subareaService.pageQuery(pageBean);
String[] excludes = new String[]{"detachedCriteria","currentPage","pageSize","decidedzone","subareas"};
this.writePageBean2Json(pageBean, excludes);
return NONE;
}
导出Excel文件提供客户下载。
1、为“导出”按钮绑定事件
//导出分区数据到excel文件中并提供下载
function doExport(){
//发送请求
window.location.href = "${pageContext.request.contextPath}/subareaAction_exportXls.action";
}
第二步:在Action中提供导出方法
/** * 使用POI写入Excel文件,提供下载 * @throws IOException */
public String exportXls() throws IOException {
List<Subarea> list = subareaService.findAll();
// 在内存中创建一个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);
dataRow.createCell(0).setCellValue(subarea.getId());
dataRow.createCell(1).setCellValue(subarea.getRegion().getId());
dataRow.createCell(2).setCellValue(subarea.getAddresskey());
Region region = subarea.getRegion();
dataRow.createCell(3).setCellValue(region.getProvince()+region.getCity()+region.getDistrict());
}
String filename = "分区数据.xls";
String agent = ServletActionContext.getRequest().getHeader("User-Agent");
filename = FileUtils.encodeDownloadFilename(filename, agent);
//一个流两个头
ServletOutputStream out = ServletActionContext.getResponse().getOutputStream();
String contentType = ServletActionContext.getServletContext().getMimeType(filename);
ServletActionContext.getResponse().setContentType(contentType);
ServletActionContext.getResponse().setHeader("content-disposition", "attchment;filename="+filename);
workbook.write(out);
return NONE;
}