今天来讲下企业的开发的一些功能应用吧,就是Ajax使用,以及简单的企业报表的导入导出,基于原有的项目进行展示(其实是本博主想偷懒)。
本系列:
文章结构:(1)Ajax使用详解(级联列表例子);(2)企业级报表Excel导入导出;
一、Ajax使用详解(级联列表例子):
(1)概述:
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
应用:
运用XHTML+CSS来表达资讯;
运用JavaScript操作DOM(Document Object Model)来执行动态效果;
运用XML和XSLT操作资料;
运用XMLHttpRequest或新的Fetch API与网页服务器进行异步资料交换;
注意:AJAX与Flash、Silverlight和Java Applet等RIA技术是有区分的。
不适用:
部分简单的表单
搜索
基本的导航
替换大量的文本
.对呈现的操纵
1. AJAX干掉了Back和History功能,即对浏览器机制的破坏。在动态更新页面的情况下,用户无法回到前一个页面状态,因为浏览器仅能记忆历史记录中的静态页面。
2. AJAX的安全问题。
AJAX技术给用户带来很好的用户体验的同时也对IT企业带来了新的安全威胁,Ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比以前更多的数据和服务器逻辑。Ajax的逻辑可以对客户端的安全扫描技术隐藏起来,允许黑客从远端服务器上建立新的攻击。还有Ajax也难以避免一些已知的安全弱点,诸如跨站点脚步攻击、SQL注入攻击和基于Credentials的安全漏洞等等。
3. 对搜索引擎支持较弱:
对搜索引擎的支持比较弱。如果使用不当,AJAX会增大网络数据的流量,从而降低整个系统的性能。
4. 违背URL和资源定位的初衷。
例如,我给你一个URL地址,如果采用了Ajax技术,也许你在该URL地址下面看到的和我在这个URL地址下看到的内容是不同的。这个和资源定位的初衷是相背离的。
5. 客户端过肥,太多客户端代码造成开发上的成本。
编写复杂、容易出错 ;冗余代码比较多(层层包含js文件是AJAX的通病,再加上以往的很多服务端代码现在放到了客户端);破坏了Web的原有标准。
简单描述工作原理:
Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给Ajax引擎自己来做, 只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
Ajax其核心有JavaScript、XMLHTTPRequest、DOM对象组成,通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据。让我们来了解这几个对象。
最基本的例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<div id="myDiv"><h2> AJAX HelloWorld</h2></div>
<button type="button" onclick="loadXMLDoc()">修改内容</button>
</script>
</head>
<body>
<script>
function loadXMLDoc(){
//在里面去使用ajax做请求,以及更新前端UI
var xmlhttp;
if (window.XMLHttpRequest){
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
}
else{
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET","/try/ajax/ajax_info.txt",true);
xmlhttp.send();
}
</script>
下面是我们今天要做的全部功能啦。
(2)级联表实现:
描述:
就是在不更新页面情况下:商品地址,会更新下面所说的对应账号(博主为了偷懒,简单写的逻辑)。
图片展示:
功能展示:选择广东省或北京市后:账号自动更新
(一)前端代码:
//注意我给select添加了一个监听喔。
<div class="modal">
<p>
<label>商品地址:</label>
<select name="location" id="location" onchange="locationChange()">
<option value="">请选择</option>
<option value="广东省">广东省</option>
<option value="北京市">北京市</option>
</select>
</p>
<p>
<label>列出对应的账号:</label>
<select name="accounts" id="accounts">
<option value="">请选择</option>
</select>
</p>
</div>
(2)方法监听就看方法嘛:方法体详解在后面(下面的例子注释使用时请删去)
//$.ajax里面就是ajax的方法啦,动态加载:
<script>
function locationChange() {
var location = $("#location").find("option:selected").text();
alert(location)
var obj = document.getElementById('accounts');//绑定select
obj.options.length = 0;
obj.add(new Option("请选择", ""));
$.ajax({
type: "post", //请求类型
url: "/ajax/findUserByProvince", //请求路径
cache: false, //缓存是否启用
data: {location: location}, //传参
dataType: "json", //期望返回的数据体
success: function (result) {
//result是后台返回给前端的结果集,而我们上面期望他是一个json,所以就是个json数组咯
if (result.length > 0) {
obj.add(new Option("请选择", ""));
for (var i in result) {//遍历取值更新select
var selectOption = new Option(result[i].account, result[i].account);
obj.add(selectOption);
}
}
}
});
}
</script>
(3)接下来看后端的处理:
@ResponseBody
@RequestMapping(value = "/findUserByProvince",produces="text/html;charset=UTF-8", method = {RequestMethod.GET,RequestMethod.POST})
public String findUserByProvince(String location){
List<User> userList = userService.findUserByProvince(location);//这个只是一个简单的根据省份去查询用户账号的逻辑,想了解细节下方有源码下载
System.out.println(JSON.toJSONString(userList));
//返回一个json数组给前端
return JSON.toJSONString(userList);
}
补充:有朋友反应下面这个jQuery使用看不太懂
//$("#location")是绑定了id是location的标签组件
//find("option:selected")是拿到上面的标签组件下面的option
//使用text()就是可以拿到内容啦。
var location = $("#location").find("option:selected").text();
这就是一个简单的级联列表实现,结合ajax。
(一)url:
要求为String类型的参数,(默认为当前页地址)发送请求的地址。
(二)type:
要求为String类型的参数,请求方式(post或get)默认为get。注意其他http请求方法,例如put和delete也可以使用,但仅部分浏览器支持。
(三)timeout:
要求为Number类型的参数,设置请求超时时间(毫秒)。此设置将覆盖$.ajaxSetup()方法的全局设置。
(四)async:
要求为Boolean类型的参数,默认设置为true,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为false。注意,同步请求将锁住浏览器,用户其他操作必须等待请求完成才可以执行。
(五)cache
要求为Boolean类型的参数,默认为true(当dataType为script时,默认为false),设置为false将不会从浏览器缓存中加载请求信息。
(六)data:
要求为Object或String类型的参数,发送到服务器的数据。如果已经不是字符串,将自动转换为字符串格式。get请求中将附加在url后。防止这种自动转换,可以查看 processData选项。对象必须为key/value格式,例如{foo1:"bar1",foo2:"bar2"}转换为&foo1=bar1&foo2=bar2。如果是数组,JQuery将自动为不同值对应同一个名称。例如{foo:["bar1","bar2"]}转换为&foo=bar1&foo=bar2。
(七)dataType:
要求为String类型的参数,预期服务器返回的数据类型。如果不指定,JQuery将自动根据http包mime信息返回responseXML或responseText,并作为回调函数参数传递。可用的类型如下:
xml:返回XML文档,可用JQuery处理。
html:返回纯文本HTML信息;包含的script标签会在插入DOM时执行。
script:返回纯文本JavaScript代码。不会自动缓存结果。除非设置了cache参数。注意在远程请求时(不在同一个域下),所有post请求都将转为get请求。
json:返回JSON数据。
jsonp:JSONP格式。使用SONP形式调用函数时,例如myurl?callback=?,JQuery将自动替换后一个“?”为正确的函数名,以执行回调函数。
text:返回纯文本字符串。
(八)beforeSend:
要求为Function类型的参数,发送请求前可以修改XMLHttpRequest对象的函数,例如添加自定义HTTP头。在beforeSend中如果返回false可以取消本次ajax请求。XMLHttpRequest对象是惟一的参数。
function(XMLHttpRequest){
this; //调用本次ajax请求时传递的options参数
}
(九)complete:
要求为Function类型的参数,请求完成后调用的回调函数(请求成功或失败时均调用)。参数:XMLHttpRequest对象和一个描述成功请求类型的字符串。
function(XMLHttpRequest, textStatus){
this; //调用本次ajax请求时传递的options参数
}
(十)success:
要求为Function类型的参数,请求成功后调用的回调函数,有两个参数。
(1)由服务器返回,并根据dataType参数进行处理后的数据。
(2)描述状态的字符串。
function(data, textStatus){
//data可能是xmlDoc、jsonObj、html、text等等
this; //调用本次ajax请求时传递的options参数
}
(十一)error:
要求为Function类型的参数,请求失败时被调用的函数。该函数有3个参数,即XMLHttpRequest对象、错误信息、捕获的错误对象(可选)。ajax事件函数如下:
function(XMLHttpRequest, textStatus, errorThrown){
//通常情况下textStatus和errorThrown只有其中一个包含信息
this; //调用本次ajax请求时传递的options参数
}
(十二)contentType:
要求为String类型的参数,当发送信息至服务器时,内容编码类型默认为"application/x-www-form-urlencoded"。该默认值适合大多数应用场合。
(十三)dataFilter:
要求为Function类型的参数,给Ajax返回的原始数据进行预处理的函数。提供data和type两个参数。data是Ajax返回的原始数据,type是调用jQuery.ajax时提供的dataType参数。函数返回的值将由jQuery进一步处理。
function(data, type){
//返回处理后的数据
return data;
}
(十四)global:
要求为Boolean类型的参数,默认为true。表示是否触发全局ajax事件。设置为false将不会触发全局ajax事件,ajaxStart或ajaxStop可用于控制各种ajax事件。
(十五)ifModified:
要求为Boolean类型的参数,默认为false。仅在服务器数据改变时获取新数据。服务器数据改变判断的依据是Last-Modified头信息。默认值是false,即忽略头信息。
(十六)jsonp:
要求为String类型的参数,在一个jsonp请求中重写回调函数的名字。该值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分,例如{jsonp:'onJsonPLoad'}会导致将"onJsonPLoad=?"传给服务器。
(十七)username:
要求为String类型的参数,用于响应HTTP访问认证请求的用户名。
(十八)password:
要求为String类型的参数,用于响应HTTP访问认证请求的密码。
(十九)processData:
要求为Boolean类型的参数,默认为true。默认情况下,发送的数据将被转换为对象(从技术角度来讲并非字符串)以配合默认内容类型"application/x-www-form-urlencoded"。如果要发送DOM树信息或者其他不希望转换的信息,请设置为false。
(二十)scriptCharset:
要求为String类型的参数,只有当请求时dataType为"jsonp"或者"script",并且type是GET时才会用于强制修改字符集(charset)。通常在本地和远程的内容编码不同时使用。
(二十一)$.each()函数:
$.each()函数不同于JQuery对象的each()方法,它是一个全局函数,不操作JQuery对象,而是以一个数组或者对象作为第1个参数,以一个回调函数作为第2个参数。回调函数拥有两个参数:第1个为对象的成员或数组的索引,第2个为对应变量或内容。
(4)涉及的重要对象:
(一)XMLHTTPRequest对象:(Ajax独有)
Ajax的一个最大的特点是无需刷新页面便可向服务器传输或读写数据(又称无刷新更新页面),这一特点主要得益于XMLHTTP组件XMLHTTPRequest对象。
方 法 |
描述 |
abort() |
停止当前请求 |
getAllResponseHeaders() |
把HTTP请求的所有响应首部作为键/值对返回 |
getResponseHeader("header") |
返回指定首部的串值 |
open("method","URL",[asyncFlag],["userName"],["password"]) |
建立对服务器的调用。method参数可以是GET、POST或PUT。url参数可以是相对URL或绝对URL。这个方法还包括3个可选的参数,是否异步,用户名,密码 |
send(content) |
向服务器发送请求 |
setRequestHeader("header", "value") |
把指定首部设置为所提供的值。在设置任何首部之前必须先调用open()。设置header并和请求一起发送 ('post'方法一定要 ) |
----- |
---- |
XMLHttpRequest 对象属性描述
属 性 |
描 述 |
onreadystatechange |
状态改变的事件触发器,每个状态改变时都会触发这个事件处理器,通常会调用一个JavaScript函数 |
readyState |
请求的状态。有5个可取值:0 = 未初始化,1 = 正在加载,2 = 已加载,3 = 交互中,4 = 完成 |
responseText |
服务器的响应,返回数据的文本。 |
responseXML |
服务器的响应,返回数据的兼容DOM的XML文档对象 ,这个对象可以解析为一个DOM对象。 |
responseBody |
服务器返回的主题(非文本格式) |
responseStream |
服务器返回的数据流 |
status |
服务器的HTTP状态码(如:404 = "文件末找到" 、200 ="成功" ,等等) |
statusText |
服务器返回的状态文本信息 ,HTTP状态码的相应文本(OK或Not Found(未找到)等等) |
(二)DOM Document Object Model
DOM是给HTML和XML文件使用的一组API。它提供了文件的结构表述,让你可以改变其中的內容及可见物。其本质是建立网页与Script或程序语言沟通的桥梁。所有WEB开发人员可操作及建立文件的属性、方法及事件都以对象来展现(例如,document就代表“文件本身“这个对像,table对象则代表HTML的表格对象等等)。这些对象可以由当今大多数的浏览器以Script来取用。一个用HTML或XHTML构建的网页也可以看作是一组结构化的数据,这些数据被封在DOM(Document Object Model)中,DOM提供了网页中各个对象的读写的支持。
二、企业级报表Excel导入导出:
(1)Excel报表导出:
实现:
(一)MAVEN对应的库先:POI、还有文件上传的包:
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
<!-- POI -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
(二)制作Excel样式:
创建个Excel文件,定义自己喜欢的颜色字体,,,就这么简单:
然后:另存为xls格式或者xlsx格式
(三)打开那个满是xml代码的文件复制到我们的jsp中
到jsp文件中:doExcel.jsp
至于数据如何接入??看下注释吧。而且!!!我们只需要在两部分写入数据解析代码,其余不要动!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.*"%>
<%@ page import="com.fuzhu.entity.GoodDetails" %>
<%
//首先看到我们上面导入的java包。然后在这里拿到后台传过来的list
String titleName = "商品列表";
response.addHeader("Content-disposition", "attachment;filename=" + (new String(titleName.getBytes("GBK"), "iso-8859-1")) + ".xls");
//拿到数据
List<String> headList=(List)request.getAttribute("headList");
List<GoodDetails> dataList=(List)request.getAttribute("resultList");
%>
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
<Created>2006-09-13T11:21:51Z</Created>
<LastSaved>2011-10-20T11:56:16Z</LastSaved>
<Version>12.00</Version>
</DocumentProperties>
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
<RemovePersonalInformation/>
</OfficeDocumentSettings>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>11640</WindowHeight>
<WindowWidth>19200</WindowWidth>
<WindowTopX>0</WindowTopX>
<WindowTopY>90</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Center"/>
<Borders/>
<Font ss:FontName="宋体" x:CharSet="134" ss:Size="11" ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="s66" ss:Name="常规 2 2 2">
<Font ss:FontName="宋体" x:CharSet="134" ss:Size="12"/>
</Style>
<Style ss:ID="s62">
<Alignment ss:Horizontal="Center" ss:Vertical="Center"/>
</Style>
<Style ss:ID="s67" ss:Parent="s66">
<Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
<Borders>
<Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"
ss:Color="#000000"/>
<Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"
ss:Color="#000000"/>
<Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"
ss:Color="#000000"/>
<Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"
ss:Color="#000000"/>
</Borders>
<Font ss:FontName="宋体" x:CharSet="134" ss:Color="#FFFFFF" ss:Bold="1"/>
<Interior ss:Color="#0066CC" ss:Pattern="Solid"/>
</Style>
<Style ss:ID="s68">
<Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
<Borders>
<Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"
ss:Color="#000000"/>
<Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"
ss:Color="#000000"/>
<Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"
ss:Color="#000000"/>
<Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"
ss:Color="#000000"/>
</Borders>
<Font ss:FontName="宋体" x:CharSet="134" ss:Size="9"/>
<Interior ss:Color="#C0C0C0" ss:Pattern="Solid"/>
</Style>
</Styles>
<!-- 文件名字-->
<Worksheet ss:Name="商品列表">
<Table ss:ExpandedColumnCount="<%=headList.size() %>" ss:ExpandedRowCount="65000" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="99" ss:DefaultRowHeight="20.0625">
<Row ss:AutoFitHeight="0" ss:Height="33.75">
<%
//看到Row没有,就是行的意思,我们要自建循环去遍历我们拿到的数据。我们先遍历头部(顶栏一般有说明的嘛),然后再去遍历数据栏
for(int i=0;i<headList.size();i++){
%>
<Cell ss:StyleID="s67"><Data ss:Type="String"><%=headList.get(i) %></Data></Cell>
<%
}
%>
</Row>
<%
//遍历数据栏
for(int x=0;x<dataList.size();x++){
%>
<Row ss:AutoFitHeight="0">
<Cell ss:StyleID="s68"><Data ss:Type="String"><%=dataList.get(x).getGoodName()==null?"":dataList.get(x).getGoodName()%></Data></Cell>
<Cell ss:StyleID="s68"><Data ss:Type="String"><%=dataList.get(x).getGoodBrand()==null?"":dataList.get(x).getGoodBrand()%></Data></Cell>
<Cell ss:StyleID="s68"><Data ss:Type="String"><%=dataList.get(x).getStoreAdd()==null?"":dataList.get(x).getStoreAdd()%></Data></Cell>
<Cell ss:StyleID="s68"><Data ss:Type="String"><%=dataList.get(x).getSellerCredit()==null?"":dataList.get(x).getSellerCredit()%></Data></Cell>
<Cell ss:StyleID="s68"><Data ss:Type="String"><%=dataList.get(x).getGoodPrice()==null?"":dataList.get(x).getGoodPrice()%></Data></Cell>
</Row>
<%
}
%>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<Unsynced/>
<Print>
<ValidPrinterInfo/>
<PaperSizeIndex>9</PaperSizeIndex>
<HorizontalResolution>200</HorizontalResolution>
<VerticalResolution>200</VerticalResolution>
</Print>
<Selected/>
<Panes>
<Pane>
<Number>3</Number>
<ActiveRow>1</ActiveRow>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
</Workbook>
(四)传给用户的Excel文件写完了,我们要怎样在后台交接数据呢??
@RequestMapping(value = "/getExcel",produces="text/html;charset=UTF-8", method = {RequestMethod.GET,RequestMethod.POST})
public String getExcel(HttpServletRequest request){
String location ="";
List<GoodDetails> goodlist = goodService.getGoodList(location);//查出数据
request.setAttribute("resultList",goodlist);
List<String> headList = new ArrayList<>();//顶栏的list
headList.add("商品名");
headList.add("商品类型");
headList.add("商品地址");
headList.add("商品星级");
headList.add("商品价格");
request.setAttribute("headList",headList);
return "doExcel";
}
这是前端点击的下载按钮。
<div style="width:100%;text-align:center">
<button><a href="getExcel">下载商品列表</a></button>
</div>
(2)Excel报表导入:
(一)给出我们的规范:让用户下载(博主顺手做多了两份模板,就给大家用啦,哈哈,见下方源码)
(二)留出我们的导入接口:
前端:
<div>
<form id="formItem" method="post" action="uploadExcel" enctype="multipart/form-data">
<div id="fileArea"
style="text-align: left; margin: 10px 10px 10px 20px;">
<p>
<label>选择导入文件:</label>
<input type="file" id="filename" name="filename" />
</p>
<input type="button" name="upload" id="upload" value="导入数据" onclick="doLoadTask()">
</div>
</form>
</div>
<div id="manualHelpTable"
style="text-align: left; margin-left: 20px;">
<table>
<tbody style="vertical-align: top;">
<tr>
<td style="white-space:nowrap;">文件类型:</td>
<td>
.xls或.xlsx电子表格文件 (1.表格中不需要留空行; 2.文件名的后缀必须是小写的".xls"或".xlsx";)
</td>
</tr>
<tr>
<td style="white-space:nowrap;">备注:</td>
<td>
<pre>导入支持新增,暂不支持修改数据,仅支持商品数据导入</pre>
</td>
</tr>
<tr>
<td style="white-space:nowrap;">导入模板:</td>
<td style="color: blue;">
<a href="../../source/plan.xls">商品表导入模板.xls</a>
<a href="../../source/plan.xls">商品表导入模板.xlsx</a>
</td>
</tr>
</tbody>
</table>
</div>
(三)利用js写好上传函数--检查文件表层规范(后缀、大小等等)、导入步骤:
function doLoadTask() {
var file = $("#filename").val();
if (file == '') {
alert("请选择待处理文件");
return;
} else {
//获取文件类型后缀
var temp = file.substring(file.lastIndexOf("\\") + 1).toString();
// alert(temp)
var extend = file.substring(file.lastIndexOf(".") + 1).toString();
// alert(extend)
if (extend == "") {
alert("请选择正确格式的文件!");
return;
} else {
if (!(extend == "xlsx") && !(extend == "xls")) {
alert("请选择正确格式的文件!");
return;
}
}
}
// var form = document.getElementById("formItem");
$("#formItem").submit();
}
(四)后端接收用户上传的文件:controller层
@Autowired
private ParseExcel parseExcel;
@RequestMapping(value = "/uploadExcel",produces="text/html;charset=UTF-8", method = {RequestMethod.GET,RequestMethod.POST})
public String uploadExcel(HttpServletRequest request ,@RequestParam(value = "filename", required = false) MultipartFile file){
String path = request.getSession().getServletContext().getRealPath("uploadExcel");
String fileName = file.getOriginalFilename();//拿到文件名
System.out.println(path);
File targetFile = new File(path, fileName);//存储的目录名
System.out.println(targetFile);
System.out.println(targetFile.toString());
if(!targetFile.exists()){
targetFile.mkdirs();//不存在目录就创建咯
}
//保存
try {
file.transferTo(targetFile);
} catch (Exception e) {
e.printStackTrace();
}
List<GoodDetails> list = null;//拿到我们导入的list后就是往数据库批量插入了,这个就太简单了,我就不写了。
if(fileName.endsWith(".xls")||fileName.endsWith(".xlsx")) {
list = parseExcel.parseExcel((File) targetFile, targetFile.toString());
}
return "success";
}
(五)接收的文件后,想要导入到数据库的前提还有一对一的数据检验以及数据获取,然后才可用对象存储方式写入数据库
//定义解析接口
public interface ParseExcel {
List<GoodDetails> parseExcel(File xlsFile,String filename);
}
一对一的数据获取与校验
@Service
public class ParseExcelImpl implements ParseExcel {
@Override
public List<GoodDetails> parseExcel(File xlsFile, String filename) {
boolean isE2007 = false; //判断是否是excel2007格式
if (filename.endsWith("xlsx"))
isE2007 = true;
System.out.println(isE2007);
List<GoodDetails> goodDetailsList = new ArrayList<>();
try {
InputStream input = new FileInputStream(filename); //建立输入流
Workbook wb = null;
//根据文件格式(2003或者2007)来初始化
if (isE2007)
wb = new XSSFWorkbook(input);//xlsx后缀
else
wb = new HSSFWorkbook(input);//xls后缀
System.out.println(wb);
Sheet sheet = wb.getSheetAt(0); //获得第一个表单
Iterator<Row> rows = sheet.rowIterator(); //获得第一个表单的迭代器
while (rows.hasNext()) {//遍历每一行
Row row = rows.next(); //获得行数据
System.out.println("Row #" + row.getRowNum()); //获得行号从0开始
Iterator<Cell> cells = row.cellIterator(); //获得第一行的迭代器
GoodDetails goodDetails = null;
if (row.getRowNum() > 0) {
goodDetails = new GoodDetails(); //每行一条记录嘛
System.out.println("第几行 " + row.getRowNum());
}
while (cells.hasNext()) {//在每一行基础上去遍历每一列
Cell cell = cells.next();//指向下一列
int i = cell.getColumnIndex();//拿到列的标记
System.out.println("Cell #" + cell.getColumnIndex());
if (goodDetails != null) {
switch (i) {//针对列去获取解析,放进我们的java对象
case 0:
goodDetails.setGoodName(String.valueOf(cell.getStringCellValue()));
break;
case 1:
goodDetails.setGoodBrand(String.valueOf(cell.getStringCellValue()));
break;
case 2:
goodDetails.setStoreAdd(String.valueOf(cell.getStringCellValue()));
break;
case 3:
goodDetails.setSellerCredit(String.valueOf(cell.getStringCellValue()));
break;
case 4:
goodDetails.setGoodPrice(String.valueOf(cell.getNumericCellValue()));
break;
default:
System.out.println("unsuported sell type");
break;
}
}
//下面这段注释代码,给大家认识下每一列对应的数据类型:
// switch (cell.getCellType()) { //根据cell中的类型来输出数据
// case HSSFCell.CELL_TYPE_NUMERIC: //读取数字
// //先看是否是日期格式
// if(HSSFDateUtil.isCellDateFormatted(cell)){
// //读取日期格式
// System.out.print("一 "+cell.getDateCellValue()+" ");
// }else{
// //读取数字
// System.out.print("一 "+cell.getNumericCellValue()+" ");
// if (goodDetails!=null){
// goodDetails.setGoodPrice(String.valueOf(cell.getNumericCellValue()));
// }
//
// }
// break;
// case HSSFCell.CELL_TYPE_STRING://读取文本对象
// System.out.println("二 "+cell.getStringCellValue());
//
// break;
// case HSSFCell.CELL_TYPE_BOOLEAN: //得到Boolean对象的方法
// System.out.println("三 "+cell.getBooleanCellValue());
// break;
// case HSSFCell.CELL_TYPE_FORMULA://得到公式
// System.out.println("四 "+cell.getCellFormula());
// break;
// default:
// System.out.println("unsuported sell type");
// break;
// }
}
goodDetailsList.add(goodDetails);//拿到我们导入的list后就是往数据库批量插入了,这个就太简单了,我就不写了。
}
System.out.println(goodDetailsList.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return goodDetailsList;
}
}
然后??下载文件,对着格式输入,然后上传
## 源码下载:[J2EE项目系列(四)--SSM框架构建积分系统和基本商品检索系统(Spring+SpringMVC+MyBatis)(3)Ajax使用详解(级联列表)以及企业级报表Excel导入导出实现](https://github.com/FuZhucheng/SSM)
### 好了,J2EE项目系列(四)--SSM框架构建积分系统和基本商品检索系统(Spring+SpringMVC+MyBatis)(3)Ajax使用详解(级联列表)以及企业级报表Excel导入导出实现讲完了,这是实习时候所学到的一些功能点,在这里写出来记录,这是积累的必经一步,我会继续出这个系列文章,分享经验给大家。欢迎在下面指出错误,共同学习!!你的点赞是对我最好的支持!!
### 更多内容,可以访问[JackFrost的博客](http://blog.csdn.net/jack__frost?viewmode=contents)