一:OCUpload
OCUpload为JQuery的插件(One Click Upload),意思为一键上传,封装了对于文件上传的一些方法,只需几行代码,文件上传优雅而简洁。
对于传统的文件上传,只是通过input标签,设置enctype为multipart/form-data,选中文件后还需点击按钮,提交表单,才能在后台进行相关字段解析,通过流来进行文件上传,上传成功后,页面多半要刷新,无法给用户良好的体验。
● OCUpload实现了页面“不刷新”,选择文件后直接上传,不需要选中文件后再点击按钮上传表单。简单实现为:
在页面的head里引入JQuery的类库,由于这里使用了easyUI使按钮和提示相对美观些,所以也导入了easyUI的核心类库,当然别忘了导入我们的OCUpload的库(本文中使用的版本是jquery.ocupload-1.1.2.js)。
首先在body中使用一个元素来“占位子”,任何标签元素都可以,不过上传文件一般点击按钮,所以我们使用easyUI的linkbutton,给按钮设置id为import.
1 <body> 2 <a id="import" class="easyui-linkbutton" data-options="iconCls:'icon-redo'">上传文档</a> 3 </body>
在head中给id为import的按钮添加upload事件,这是OCUpload的上传方法,参数为json对象,由于是简单入门,在这里即使用三个主要的属性:action(处理上传文件的后台action路径),name(给文件设置name,便于后台通过name获取),onComplete(参数为function,执行上传完毕的回调函数)。
1 <script type="text/javascript"> 2 $(function(){ 3 $("#import").upload({ 4 action:'${pageContext.request.contextPath}/regionAction_importXls', 5 name:'upload', 6 onComplete: function (data, self, element) { 7 if(data=='1'){ 8 $.messager.alert("提示信息","数据导入成功!","info"); 9 }else{ 10 $.messager.alert("提示信息","数据导入失败!","info"); 11 } 12 location.reload(); 13 } 14 }); 15 }); 16 </script>
到此便完成一键上传的前台代码,只需要后台对上传文件进行解析处理即可完成文件上传。
让我们来看看这些代码做了些什么。访问页面,打开F12调试。
可以看到,OCUpload将我们的linkbutton底部添加了一个带有文件input的form和一个display:none 不可见的iframe。
● 选择文件后form中的input触发onChange事件,直接提交表单,实现了选择文件后直接上传
● 文件上传后,本来页面是要刷新的,但是OCUpload将target指向底部隐藏的iframe,使得隐藏的iframe刷新,从而达到我们的页面“不刷新”的效果
二:POI
(1)xls文件解析
在后台使用poi对上传的xls文件进行解析,将文件中的一行(row)解析成javabean,通过hibernate存入数据库。
1 public class RegionAction extends BaseAction<Region> { 2 3 private File upload; 4 5 public String importXls() throws FileNotFoundException, IOException { 6 HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(upload));//此为poi的核心对象,通过构造方法中的InputStream生成HSSWorkbook对象。 7 HSSFSheet sheetAt = workbook.getSheetAt(0);//这里得到第一张表格(sheet) 8 List<Region> regions = new ArrayList<Region>(); 9 for (Row row : sheetAt) { 10 //通过遍历sheetAt获取每一行(row),再通过每一行获取每一个值 11 String value1 = row.getCell(0).getStringCellValue();//id 12 String value2 = row.getCell(1).getStringCellValue();//province 13 String value3 = row.getCell(2).getStringCellValue();//city 14 String value4 = row.getCell(3).getStringCellValue();//district 15 String value5 = row.getCell(4).getStringCellValue();//postcode 16 Region region = new Region(value1, value2, value3, value4, value5); 17 region.setShortcode(StringUtils.join(PinYin4jUtils.getHeadByString(value2+value3), ""));//此处利用PinYin4jUtils将表格中的字段转成拼音封装到javabean,暂且不提 18 region.setCitycode(PinYin4jUtils.hanziToPinyin(value3)); 19 regions.add(region); 20 } 21 String flag = "1"; 22 try{ 23 regionService.saveBatch(regions);//批处理保存到数据库中,如果抛异常返回标志字符串回前台,做出相应友好提示 24 }catch(Exception e){ 25 flag = "0"; 26 } 27 ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8"); 28 ServletActionContext.getResponse().getWriter().print(flag); 29 return NONE;//上传文件,不需要配视图 30 } 31 }
那么在poi中,sheet、row、cell分别是什么呢?
-
sheet: xls中的工作表
-
row: xls中的行
-
cell: xls中的每一个数据
(2)xls文件生成
在后台查询出数据list,封装进HSSFWorkbook对象生成xls文件,提供一个输出流,告知浏览器文件名和文件类型,在前台提供按钮或链接,指向此action,实现xls文件导出。
1 //数据导出 2 public String exportXls() throws IOException { 3 //第一步:查询所有的分区数据 4 List<Subarea> list = subareaService.findAll(); 5 6 //第二步:使用POI将数据写到Excel文件中 7 HSSFWorkbook workbook = new HSSFWorkbook(); 8 HSSFSheet sheet = workbook.createSheet("分区数据"); 9 //创建标题行 10 HSSFRow headRow = sheet.createRow(0); 11 headRow.createCell(0).setCellValue("分区编号"); 12 headRow.createCell(1).setCellValue("起始号"); 13 headRow.createCell(2).setCellValue("终止号"); 14 headRow.createCell(3).setCellValue("位置"); 15 headRow.createCell(4).setCellValue("省市区"); 16 for (Subarea subarea : list) { 17 HSSFRow dataRow = sheet.createRow(sheet.getLastRowNum() + 1); 18 dataRow.createCell(0).setCellValue(subarea.getId()); 19 dataRow.createCell(1).setCellValue(subarea.getStartnum()); 20 dataRow.createCell(2).setCellValue(subarea.getEndnum()); 21 dataRow.createCell(3).setCellValue(subarea.getPosition()); 22 dataRow.createCell(4).setCellValue(subarea.getRegion().getName()); 23 } 24 25 //第三步:使用输出流进行文件下载(一个流、两个头) 26 String filename = "分区数据.xls"; 27 String contentType = ServletActionContext.getServletContext().getMimeType(filename); 28 29 ServletOutputStream out = ServletActionContext.getResponse().getOutputStream(); 30 ServletActionContext.getResponse().setContentType(contentType); 31 String agent = ServletActionContext.getRequest().getHeader("User-Agent"); 32 filename = FileUtils.encodeDownloadFilename(filename, agent); 33 ServletActionContext.getResponse().setHeader("content-disposition", "attachment;filename="+filename); 34 workbook.write(out); 35 36 return NONE; 37 }
下载文件时,针对不同浏览器,进行附件名的编码源码如下:
1 public class FileUtils { 2 /** 3 * 下载文件时,针对不同浏览器,进行附件名的编码 4 * 5 * @param filename 6 * 下载文件名 7 * @param agent 8 * 客户端浏览器 9 */ 10 public static String encodeDownloadFilename(String filename, String agent) 11 throws IOException { 12 if (agent.contains("MSIE")) { 13 // IE浏览器 14 filename = URLEncoder.encode(filename, "utf-8"); 15 filename = filename.replace("+", " "); 16 } else if (agent.contains("Firefox")) { 17 // 火狐浏览器 18 filename = "=?utf-8?B?" + new BASE64Encoder().encode(filename.getBytes("utf-8")) + "?="; 19 } else { 20 // 其它浏览器 21 filename = URLEncoder.encode(filename, "utf-8"); 22 } 23 return filename; 24 } 25 }
三:PinYin4j
主要利用PinYin4jUtils的相关方法进行汉字转拼音。
PinYin4jUtils源码如下:
1 package zhan.utils; 2 3 import java.util.Arrays; 4 5 import net.sourceforge.pinyin4j.PinyinHelper; 6 import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; 7 import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; 8 import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; 9 import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 10 11 public class PinYin4jUtils { 12 /** 13 * 将字符串转换成拼音数组 14 */ 15 public static String[] stringToPinyin(String src) { 16 return stringToPinyin(src, false, null); 17 } 18 19 /** 20 * 将字符串转换成拼音数组 21 */ 22 public static String[] stringToPinyin(String src, String separator) { 23 24 return stringToPinyin(src, true, separator); 25 } 26 27 /** 28 * 将字符串转换成拼音数组 29 * 30 * @param src 31 * @param isPolyphone 32 * 是否查出多音字的所有拼音 33 * @param separator 34 * 多音字拼音之间的分隔符 35 * @return 36 */ 37 public static String[] stringToPinyin(String src, boolean isPolyphone, 38 String separator) { 39 // 判断字符串是否为空 40 if ("".equals(src) || null == src) { 41 return null; 42 } 43 char[] srcChar = src.toCharArray(); 44 int srcCount = srcChar.length; 45 String[] srcStr = new String[srcCount]; 46 47 for (int i = 0; i < srcCount; i++) { 48 srcStr[i] = charToPinyin(srcChar[i], isPolyphone, separator); 49 } 50 return srcStr; 51 } 52 53 /** 54 * 将单个字符转换成拼音 55 * 56 * @param src 57 * @return 58 */ 59 public static String charToPinyin(char src, boolean isPolyphone, 60 String separator) { 61 // 创建汉语拼音处理类 62 HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); 63 // 输出设置,大小写,音标方式 64 defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); 65 defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); 66 67 StringBuffer tempPinying = new StringBuffer(); 68 69 // 如果是中文 70 if (src > 128) { 71 try { 72 // 转换得出结果 73 String[] strs = PinyinHelper.toHanyuPinyinStringArray(src, 74 defaultFormat); 75 76 // 是否查出多音字,默认是查出多音字的第一个字符 77 if (isPolyphone && null != separator) { 78 for (int i = 0; i < strs.length; i++) { 79 tempPinying.append(strs[i]); 80 if (strs.length != (i + 1)) { 81 // 多音字之间用特殊符号间隔起来 82 tempPinying.append(separator); 83 } 84 } 85 } else { 86 tempPinying.append(strs[0]); 87 } 88 89 } catch (BadHanyuPinyinOutputFormatCombination e) { 90 e.printStackTrace(); 91 } 92 } else { 93 tempPinying.append(src); 94 } 95 96 return tempPinying.toString(); 97 98 } 99 100 public static String hanziToPinyin(String hanzi) { 101 return hanziToPinyin(hanzi, " "); 102 } 103 104 /** 105 * 将汉字转换成拼音 106 * 107 * @param hanzi 108 * @param separator 109 * @return 110 */ 111 public static String hanziToPinyin(String hanzi, String separator) { 112 113 // 创建汉语拼音处理类 114 HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); 115 // 输出设置,大小写,音标方式 116 defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); 117 defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); 118 119 String pinyingStr = ""; 120 try { 121 pinyingStr = PinyinHelper.toHanyuPinyinString(hanzi, defaultFormat, 122 separator); 123 } catch (BadHanyuPinyinOutputFormatCombination e) { 124 // TODO Auto-generated catch block 125 e.printStackTrace(); 126 } 127 return pinyingStr; 128 } 129 130 /** 131 * 将字符串数组转换成字符串 132 * 133 * @param str 134 * @param separator 135 * 各个字符串之间的分隔符 136 * @return 137 */ 138 public static String stringArrayToString(String[] str, String separator) { 139 StringBuffer sb = new StringBuffer(); 140 for (int i = 0; i < str.length; i++) { 141 sb.append(str[i]); 142 if (str.length != (i + 1)) { 143 sb.append(separator); 144 } 145 } 146 return sb.toString(); 147 } 148 149 /** 150 * 简单的将各个字符数组之间连接起来 151 * 152 * @param str 153 * @return 154 */ 155 public static String stringArrayToString(String[] str) { 156 return stringArrayToString(str, ""); 157 } 158 159 /** 160 * 将字符数组转换成字符串 161 * 162 * @param str 163 * @param separator 164 * 各个字符串之间的分隔符 165 * @return 166 */ 167 public static String charArrayToString(char[] ch, String separator) { 168 StringBuffer sb = new StringBuffer(); 169 for (int i = 0; i < ch.length; i++) { 170 sb.append(ch[i]); 171 if (ch.length != (i + 1)) { 172 sb.append(separator); 173 } 174 } 175 return sb.toString(); 176 } 177 178 /** 179 * 将字符数组转换成字符串 180 * 181 * @param str 182 * @return 183 */ 184 public static String charArrayToString(char[] ch) { 185 return charArrayToString(ch, " "); 186 } 187 188 /** 189 * 取汉字的首字母 190 * 191 * @param src 192 * @param isCapital 193 * 是否是大写 194 * @return 195 */ 196 public static char[] getHeadByChar(char src, boolean isCapital) { 197 // 如果不是汉字直接返回 198 if (src <= 128) { 199 return new char[] { src }; 200 } 201 // 获取所有的拼音 202 String[] pinyingStr = PinyinHelper.toHanyuPinyinStringArray(src); 203 204 // 创建返回对象 205 int polyphoneSize = pinyingStr.length; 206 char[] headChars = new char[polyphoneSize]; 207 int i = 0; 208 // 截取首字符 209 for (String s : pinyingStr) { 210 char headChar = s.charAt(0); 211 // 首字母是否大写,默认是小写 212 if (isCapital) { 213 headChars[i] = Character.toUpperCase(headChar); 214 } else { 215 headChars[i] = headChar; 216 } 217 i++; 218 } 219 220 return headChars; 221 } 222 223 /** 224 * 取汉字的首字母(默认是大写) 225 * 226 * @param src 227 * @return 228 */ 229 public static char[] getHeadByChar(char src) { 230 return getHeadByChar(src, true); 231 } 232 233 /** 234 * 查找字符串首字母 235 * 236 * @param src 237 * @return 238 */ 239 public static String[] getHeadByString(String src) { 240 return getHeadByString(src, true); 241 } 242 243 /** 244 * 查找字符串首字母 245 * 246 * @param src 247 * @param isCapital 248 * 是否大写 249 * @return 250 */ 251 public static String[] getHeadByString(String src, boolean isCapital) { 252 return getHeadByString(src, isCapital, null); 253 } 254 255 /** 256 * 查找字符串首字母 257 * 258 * @param src 259 * @param isCapital 260 * 是否大写 261 * @param separator 262 * 分隔符 263 * @return 264 */ 265 public static String[] getHeadByString(String src, boolean isCapital, 266 String separator) { 267 char[] chars = src.toCharArray(); 268 String[] headString = new String[chars.length]; 269 int i = 0; 270 for (char ch : chars) { 271 272 char[] chs = getHeadByChar(ch, isCapital); 273 StringBuffer sb = new StringBuffer(); 274 if (null != separator) { 275 int j = 1; 276 277 for (char ch1 : chs) { 278 sb.append(ch1); 279 if (j != chs.length) { 280 sb.append(separator); 281 } 282 j++; 283 } 284 } else { 285 sb.append(chs[0]); 286 } 287 headString[i] = sb.toString(); 288 i++; 289 } 290 return headString; 291 } 292 293 public static void main(String[] args) { 294 // pin4j 简码 和 城市编码 295 String s1 = "中华人民共和国"; 296 String[] headArray = getHeadByString(s1); // 获得每个汉字拼音首字母 297 System.out.println(Arrays.toString(headArray)); 298 299 String s2 ="长城" ; 300 System.out.println(Arrays.toString(stringToPinyin(s2,true,","))); 301 302 String s3 ="长"; 303 System.out.println(Arrays.toString(stringToPinyin(s3,true,","))); 304 } 305 }