J2EE项目系列(四)--SSM框架构建积分系统和基本商品检索系统(Spring+SpringMVC+MyBatis)(3)Ajax使用详解(级联列表)以及企业级报表Excel导入导出实现

今天来讲下企业的开发的一些功能应用吧,就是Ajax使用,以及简单的企业报表的导入导出,基于原有的项目进行展示(其实是本博主想偷懒)。

本系列:

(一)项目框架整合构建

(二)建立商品数据库和Lucene的搭建

(三) Redis系列(一)--安装、helloworld以及读懂配置文件

(四)Redis系列(二)--缓存设计(整表缓存以及排行榜缓存方案实现)

(五) Lucene总结系列(一)--认识、helloworld以及基本的api操作。

(六)Lucene总结系列(二)--商品检索系统的文字检索业务(lucene项目使用)

(七)Lucene总结系列(三)--总述优化方案和呈现实时内存索引实现(结合RAMDirectory源码解析)

(八)JavaWeb--Servlet过滤器Filter和SpringMVC的HandlerInterceptor(Session和Cookie登录认证)

(九)Redis系列(三)--过期策略

(十)Redis系列(四)--内存淘汰机制(含单机版内存优化建议)


文章结构:(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)级联表实现:

描述:
就是在不更新页面情况下:商品地址,会更新下面所说的对应账号(博主为了偷懒,简单写的逻辑)。
图片展示:
这里写图片描述
这里写图片描述
功能展示:选择广东省或北京市后:账号自动更新
这里写图片描述

实现:demo代码

(一)前端代码:

//注意我给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。


(3)下面就详细讲解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>&nbsp;&nbsp;&nbsp;
                <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)                 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • AJAX 原生js操作ajax 1.创建XMLHttpRequest对象 var xhr = new XMLHtt...
    碧玉含香阅读 3,051评论 0 7
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,500评论 6 13
  • 本文详细介绍了 XMLHttpRequest 相关知识,涉及内容: AJAX、XMLHTTP、XMLHttpReq...
    semlinker阅读 13,512评论 2 18
  • 五十三:请解释 JavaScript 中 this 是如何工作的。1.方法调用模式当一个函数被保存为一个对象的属性...
    Arno_z阅读 520评论 0 2
  • 你可以 撕毁我的文章 烧掉我的衣裳 你可以 让我遍体鳞伤 甚至死亡 但是你用永远 也别妄想 毁掉我的学识 攫取我的...
    文展阅读 242评论 13 2