框架 day50 BOS项目 4 批量导入(ocupload插件,pinyin4J)/POI解析Excel/Combobox下拉框/分区组合条件分页查询(ajax)/分区数据导出(Excel)

知识点:

批量导入(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>
时间: 2024-08-01 10:45:01

框架 day50 BOS项目 4 批量导入(ocupload插件,pinyin4J)/POI解析Excel/Combobox下拉框/分区组合条件分页查询(ajax)/分区数据导出(Excel)的相关文章

bos 第4 (区域excel批量导入、区域通用分页查询、分区的添加、分区多条件分页查询、分区导出excel)

BOS项目笔记 第4天 今天内容安排: 1.区域批量导入功能 jQuery OCUpload(一键上传插件).apache POI.pinyin4j 2.实现区域的分页查询 3.对分页代码重构 4.添加分区(combobox下拉框) 5.分区的组合条件分页查询 6.分区数据导出功能 1. 区域数据批量导入功能 1.1 一键上传插件使用 ajax不能做文件上传. 第一步:在jsp页面中引入插件的js文件 <script type="text/javascript" src=&quo

框架 day58 BOS项目练习(基于activiti物流配送流程,启动,查询,办理,项目知识点复习)

BOS项目笔记第12天 内容: 1.设计物流配送流程 2.启动物流配送流程 3.查询组任务.拾取组任务 4.查询个人任务.办理个人任务 1.    设计物流配送流程     物流配送流程 基于组任务进行任务分配.使用排他网关,分支选择使用流程变量实现 Activiti图形界面中: Process的Id值 对应流程定义表中的key值,可以用于启动最新版本的流程实例 任务节点中: General的 Id值对应任务表中的Task_def_key既 taskDefinitionKey值,用于定义项目中

框架 day49 BOS项目练习3(修复window控件BUG,添加/修改/作废取派员,datagrid使用,分页查询(DetachedCriteria离线),formatter函数)

BOS项目笔记第3天 1.    修复window控件bug 把弹出窗口拖动到浏览器窗口外之后无法再拖动     将提供的outOfBounds.js文件复制到项目中     在需要修复的jsp页面引入js文件,可以阻止控件拖出窗口 <script src="${pageContext.request.contextPath }/js/easyui/outOfBounds.js" type="text/javascript"></script&

框架 day51 BOS项目练习(定区添加及查询,Hessian入门,基于hessian实现定区关联客户功能)

BOS项目笔记第5天 1.    定区添加功能 什么是定区?定区将客户信息.取派员.分区信息关联到一起,为自动分单提供数据. 1.1   在下拉框中展示取派员数据 第一步:修改combobox的url地址,访问StaffAction的listajax方法,查询取派员数据 第二步:在StaffAction中提供方法 /** * ajax查询未作废的员工 * @return */ public String findByWorking(){ List<Staff> list=staffServic

框架学习日志(4):如何通过Ajax进行分页查询并绑定数据?

需求设定 1.在页面中通过Ajax发送请求至程序后端对User表进行分页查询,将数据展示至页面上: 2.要求显示字段:主键.姓名.年龄.出生年份.性别.职位: 3.需要统计总数.可上下翻页.可指定页跳转: User表 Position字段,int型,值范围0-5,依次工作职位:实习生.普通职工.资深职工.团队组长.部门经理.公司经理. 以上为情景设定,接下来进入代码实战. 新建类库,搭建开发流程 User表属于账户管理模块,所以我们将新建的类库取名为Account. 分别在各层建立如下类库.文件

解决Bui框架下拉框select配合Gird弹出模态编辑框使用,无法选取编辑行的下拉内容.

这个需求比较简单,就是下拉列表的项是异步请求过来的加载的,而点击gird的编辑一行按钮实现动态选择表单的行内容: 点击编辑效果: 图中的RulesDictID项是从后台异步获取的.那么我们在前端这样写: <div class="row-fluid"> <div class="span24"> <div class="panel"> <div class="panel-header"&g

关于下拉框插件、或者框架的下拉框,初始化之后无法联动,或者再次绑定值问题

我用的Bootstrap4的ubold 框架 ,他的下拉框第一次初始化之后,再次初始化,就不在赋值了. 第一步,我审查了元素, 下拉框是没有花里胡哨的样式的,基本上美化下拉框是根据返回的select 数据 生成一个ul li 然后把生成的元素重新赋值. 根据我多次测试和操作,个人分析,造成第二次不绑定数据的原因是:那个初始化方法只会给未生成的元素初始样式,已有的就不会再次初始样式了.(有些框架不会,但是有些会这样) 第二步,根据原因解决(原则上来说,为达目的不择手段) 1.可以把他写的JS找到,

框架 day55 BOS项目练习(工作流,activiti入门)

BOS项目笔记第9天 内容: 1.工作流概念 2.安装eclipse插件(工作流流程设计器插件) 3.创建activiti框架提供的数据库表结构(23张表) 4.学习工作流框架API,操作流程 1.    工作流概念 工作流(Workflow),就是"业务过程的部分或整体在计算机应用环境下的自动化",它主要解决的是"使在多个参与者之间按照某种预定义的规则传递文档.信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现".(按照某种预定义的规则来执

框架 day47 BOS项目练习1(项目概述,环境,页面[easyUI,Ztree],数据库PowerDesigner)

1.    项目概述 1.1   项目背景介绍 BOS(Bussiness Operating System)-----业务操作系统 本项目物流BOS项目分为基础设置.取派.中转.路由.报表部分 1.2   常见的软件项目类型 OA:办公自动化系统 CRM:客户关系管理系统 ERP:企业资源计划平台 CMS:内容管理系统 BBS:论坛系统 1.3   项目开发流程(瀑布模型) 1.  需求调研分析----需求规格说明书 2.  设计阶段(概要设计.详细设计)------数据库设计文档.原型 3.