SpringBoot實(shí)現(xiàn)Excel讀取的實(shí)例教程
前言
這是本人寫的一個(gè)SpringBoot對(duì)Excel讀取的方法,實(shí)測(cè)能用,待提升的地方有很多,有不足之處請(qǐng)多多指點(diǎn)。
Excel2003版(后綴為.xls)最大行數(shù)是65536行,最大列數(shù)是256列。
Excel2007以上的版本(后綴為.xlsx)最大行數(shù)是1048576行,最大列數(shù)是16384列。
提供2種方法讀?。?br />
1.根據(jù)指定的開始和結(jié)束行數(shù)讀取返回結(jié)果,結(jié)果格式為L(zhǎng)ist<Map<String, Object>>
2.根據(jù)指定的開始和結(jié)束行數(shù)讀取返回結(jié)果,結(jié)果格式為L(zhǎng)ist<POJO(傳入的實(shí)體類)>
請(qǐng)根據(jù)實(shí)際內(nèi)存堆可用大小進(jìn)行讀取,太多可進(jìn)行分段讀?。愃品猪?yè)的原理)
讀取Excel所需要的幾個(gè)類

1.在pom.xml加上依賴
</dependencies> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version> </dependency> </dependencies>
2.ExcelPOJO實(shí)體類
package com.cly.utils.Excel;
/**
* @author : CLy
* @ClassName : ExcelPOJO
* @date : 2020/7/9 17:13
* 實(shí)體類所有成員變量都需要有GET,SET方法
* 所有成員變量都要加上注解@excelRescoure(value = "?"),?為Excel真實(shí)列名,必須一一對(duì)應(yīng)
* @excelRescoure(value = "?"),?可為空,需要用到才賦值
* 成員變量目前只允許String,Double,Interge,Float
**/
public class ExcelPOJO {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPasswork() {
return passwork;
}
public void setPasswork(String passwork) {
this.passwork = passwork;
}
public String getLook() {
return look;
}
public void setLook(String look) {
this.look = look;
}
@excelRescoure(value = "XM")
private String name;
@excelRescoure(value = "SFZH")
private String passwork;
@excelRescoure()
private String look;
@Override
public String toString(){
return "name:"+this.getName()+",passwork:"+this.getPasswork()+",look:"+this.getLook();
}
public ExcelPOJO() {}
}
3.@interface自定義注解(用于實(shí)體類讀取)
package com.cly.utils.Excel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author : CLy
* @ClassName : myRescoure
* @date : 2020/7/10 9:31
**/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface excelRescoure {
String value() default "";//默認(rèn)為空
}
4.excelRead類(讀取Excel數(shù)據(jù)類)有很多冗余的代碼,可抽離出來(lái)
package com.cly.utils.Excel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.transform.Source;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.*;
import java.text.DecimalFormat;
import java.util.*;
/**
* @author : CLy
* @ClassName : excelRead
* @date : 2020/7/9 11:08
**/
public class excelRead {
//日志輸出
private static Logger logger = LoggerFactory.getLogger(excelRead.class);
//定義excel類型
private static final String XLS = "xls";
private static final String XLSX = "xlsx";
/**
* 根據(jù)文件后綴名類型獲取對(duì)應(yīng)的工作簿對(duì)象
* @param inputStream 讀取文件的輸入流
* @param fileType 文件后綴名類型(xls或xlsx)
* @return 包含文件數(shù)據(jù)的工作簿對(duì)象
*/
private static Workbook getWorkbook(InputStream inputStream, String fileType) throws IOException {
//用自帶的方法新建工作薄
Workbook workbook = WorkbookFactory.create(inputStream);
//后綴判斷有版本轉(zhuǎn)換問(wèn)題
//Workbook workbook = null;
//if (fileType.equalsIgnoreCase(XLS)) {
// workbook = new HSSFWorkbook(inputStream);
//} else if (fileType.equalsIgnoreCase(XLSX)) {
// workbook = new XSSFWorkbook(inputStream);
//}
return workbook;
}
/**
* 將單元格內(nèi)容轉(zhuǎn)換為字符串
* @param cell
* @return
*/
private static String convertCellValueToString(Cell cell) {
if (cell == null) {
return null;
}
String returnValue = null;
switch (cell.getCellType()) {
case NUMERIC: //數(shù)字
Double doubleValue = cell.getNumericCellValue();
// 格式化科學(xué)計(jì)數(shù)法,取一位整數(shù),如取小數(shù),值如0.0,取小數(shù)點(diǎn)后幾位就寫幾個(gè)0
DecimalFormat df = new DecimalFormat("0");
returnValue = df.format(doubleValue);
break;
case STRING: //字符串
returnValue = cell.getStringCellValue();
break;
case BOOLEAN: //布爾
Boolean booleanValue = cell.getBooleanCellValue();
returnValue = booleanValue.toString();
break;
case BLANK: // 空值
break;
case FORMULA: // 公式
returnValue = cell.getCellFormula();
break;
case ERROR: // 故障
break;
default:
break;
}
return returnValue;
}
/**
* 處理Excel內(nèi)容轉(zhuǎn)為L(zhǎng)ist<Map<String,Object>>輸出
* workbook:已連接的工作薄
* StatrRow:讀取的開始行數(shù)(默認(rèn)填0,0開始,傳過(guò)來(lái)是EXcel的行數(shù)值默認(rèn)從1開始,這里已處理減1)
* EndRow:讀取的結(jié)束行數(shù)(填-1為全部)
* ExistTop:是否存在頭部(如存在則讀取數(shù)據(jù)時(shí)會(huì)把頭部拼接到對(duì)應(yīng)數(shù)據(jù),若無(wú)則為當(dāng)前列數(shù))
*/
private static List<Map<String, Object>> HandleData(Workbook workbook, int StatrRow, int EndRow, boolean ExistTop) {
//聲明返回結(jié)果集result
List<Map<String, Object>> result = new ArrayList<>();
//聲明一個(gè)Excel頭部函數(shù)
ArrayList<String> top = new ArrayList<>();
//解析sheet(sheet是Excel腳頁(yè))
/**
*此處會(huì)讀取所有腳頁(yè)的行數(shù)據(jù),若只想讀取指定頁(yè),不要for循環(huán),直接給sheetNum賦值,腳頁(yè)從0開始(通常情況Excel都只有一頁(yè),所以此處未進(jìn)行進(jìn)一步處理)
*/
for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
Sheet sheet = workbook.getSheetAt(sheetNum);
// 校驗(yàn)sheet是否合法
if (sheet == null) {
continue;
}
//如存在頭部,處理頭部數(shù)據(jù)
if (ExistTop) {
int firstRowNum = sheet.getFirstRowNum();
Row firstRow = sheet.getRow(firstRowNum);
if (null == firstRow) {
logger.warn("解析Excel失敗,在第一行沒(méi)有讀取到任何數(shù)據(jù)!");
}
for (int i = 0; i < firstRow.getLastCellNum(); i++) {
top.add(convertCellValueToString(firstRow.getCell(i)));
}
}
//處理Excel數(shù)據(jù)內(nèi)容
int endRowNum;
//獲取結(jié)束行數(shù)
if (EndRow == -1) {
endRowNum = sheet.getPhysicalNumberOfRows();
} else {
endRowNum = EndRow <= sheet.getPhysicalNumberOfRows() ? EndRow : sheet.getPhysicalNumberOfRows();
}
//遍歷行數(shù)
for (int i = StatrRow - 1; i < endRowNum; i++) {
Row row = sheet.getRow(i);
if (null == row) {
continue;
}
Map<String, Object> map = new HashMap<>();
//獲取所有列數(shù)據(jù)
for (int y = 0; y < row.getLastCellNum(); y++) {
if (top.size() > 0) {
if (top.size() >= y) {
map.put(top.get(y), convertCellValueToString(row.getCell(y)));
} else {
map.put(String.valueOf(y + 1), convertCellValueToString(row.getCell(y)));
}
} else {
map.put(String.valueOf(y + 1), convertCellValueToString(row.getCell(y)));
}
}
result.add(map);
}
}
return result;
}
/**
* 方法一
* 根據(jù)行數(shù)和列數(shù)讀取Excel
* fileName:Excel文件路徑
* StatrRow:讀取的開始行數(shù)(默認(rèn)填0)
* EndRow:讀取的結(jié)束行數(shù)(填-1為全部)
* ExistTop:是否存在頭部(如存在則讀取數(shù)據(jù)時(shí)會(huì)把頭部拼接到對(duì)應(yīng)數(shù)據(jù),若無(wú)則為當(dāng)前列數(shù))
* 返回一個(gè)List<Map<String,Object>>
*/
public static List<Map<String, Object>> ReadExcelByRC(String fileName, int StatrRow, int EndRow, boolean ExistTop) {
//判斷輸入的開始值是否少于等于結(jié)束值
if (StatrRow > EndRow && EndRow != -1) {
logger.warn("輸入的開始行值比結(jié)束行值大,請(qǐng)重新輸入正確的行數(shù)");
List<Map<String, Object>> error = null;
return error;
}
//聲明返回的結(jié)果集
List<Map<String, Object>> result = new ArrayList<>();
//聲明一個(gè)工作薄
Workbook workbook = null;
//聲明一個(gè)文件輸入流
FileInputStream inputStream = null;
try {
// 獲取Excel后綴名,判斷文件類型
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
// 獲取Excel文件
File excelFile = new File(fileName);
if (!excelFile.exists()) {
logger.warn("指定的Excel文件不存在!");
return null;
}
// 獲取Excel工作簿
inputStream = new FileInputStream(excelFile);
workbook = getWorkbook(inputStream, fileType);
//處理Excel內(nèi)容
result = HandleData(workbook, StatrRow, EndRow, ExistTop);
} catch (Exception e) {
logger.warn("解析Excel失敗,文件名:" + fileName + " 錯(cuò)誤信息:" + e.getMessage());
} finally {
try {
if (null != workbook) {
workbook.close();
}
if (null != inputStream) {
inputStream.close();
}
} catch (Exception e) {
logger.warn("關(guān)閉數(shù)據(jù)流出錯(cuò)!錯(cuò)誤信息:" + e.getMessage());
return null;
}
}
return result;
}
/**==============================================================================================================================**/
/**
* 方法二
* 根據(jù)給定的實(shí)體類中賦值的注解值讀取Excel
* fileName:Excel文件路徑
* StatrRow:讀取的開始行數(shù)(默認(rèn)填0)
* EndRow:讀取的結(jié)束行數(shù)(填-1為全部)
* Class<T>:傳過(guò)來(lái)的實(shí)體類類型
* 返回一個(gè)List<T>:T為實(shí)體類
*/
public static List<Object> ReadExcelByPOJO(String fileName, int StatrRow, int EndRow, Class t) throws InvocationTargetException, IntrospectionException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//判斷輸入的開始值是否少于等于結(jié)束值
if (StatrRow > EndRow && EndRow != -1) {
logger.warn("輸入的開始行值比結(jié)束行值大,請(qǐng)重新輸入正確的行數(shù)");
List<Object> error = null;
return error;
}
//聲明返回的結(jié)果集
List<Object> result = new ArrayList<>();
//聲明一個(gè)工作薄
Workbook workbook = null;
//聲明一個(gè)文件輸入流
FileInputStream inputStream = null;
try {
// 獲取Excel后綴名,判斷文件類型
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
// 獲取Excel文件
File excelFile = new File(fileName);
if (!excelFile.exists()) {
logger.warn("指定的Excel文件不存在!");
return null;
}
// 獲取Excel工作簿
inputStream = new FileInputStream(excelFile);
workbook = getWorkbook(inputStream, fileType);
//處理Excel內(nèi)容
result = HandleDataPOJO(workbook, StatrRow, EndRow, t);
} catch (Exception e) {
logger.warn("解析Excel失敗,文件名:" + fileName + " 錯(cuò)誤信息:" + e.getMessage());
} finally {
try {
if (null != workbook) {
workbook.close();
}
if (null != inputStream) {
inputStream.close();
}
} catch (Exception e) {
logger.warn("關(guān)閉數(shù)據(jù)流出錯(cuò)!錯(cuò)誤信息:" + e.getMessage());
return null;
}
}
return result;
}
/**
* 處理Excel內(nèi)容轉(zhuǎn)為L(zhǎng)ist<T>輸出
* workbook:已連接的工作薄
* StatrRow:讀取的開始行數(shù)(默認(rèn)填0,0開始,傳過(guò)來(lái)是EXcel的行數(shù)值默認(rèn)從1開始,這里已處理減1)
* EndRow:讀取的結(jié)束行數(shù)(填-1為全部)
* Class<T>:所映射的實(shí)體類
*/
private static <t> List<Object> HandleDataPOJO(Workbook workbook, int StatrRow, int EndRow, Class<?> t) throws IntrospectionException, NoSuchFieldException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException {
//聲明返回的結(jié)果集
List<Object> result = new ArrayList<Object>();
//解析sheet(sheet是Excel腳頁(yè))
for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
Sheet sheet = workbook.getSheetAt(sheetNum);
// 校驗(yàn)sheet是否合法
if (sheet == null) {
continue;
}
//獲取頭部數(shù)據(jù)
//聲明頭部數(shù)據(jù)數(shù)列對(duì)象
ArrayList<String> top = new ArrayList<>();
//獲取Excel第一行數(shù)據(jù)
int firstRowNum = sheet.getFirstRowNum();
Row firstRow = sheet.getRow(firstRowNum);
if (null == firstRow) {
logger.warn("解析Excel失敗,在第一行沒(méi)有讀取到任何數(shù)據(jù)!");
return null;
}
for (int i = 0; i < firstRow.getLastCellNum(); i++) {
top.add(convertCellValueToString(firstRow.getCell(i)));
}
//獲取實(shí)體類的成原變量
Map<String, Object> POJOfields = getPOJOFieldAndValue(t);
//判斷所需要的數(shù)據(jù)列
Map<String, Object> exceltoPOJO = new HashMap<>();
for (int i = 0; i < top.size(); i++) {
if (POJOfields.get(top.get(i)) != null && !"".equals(POJOfields.get(top.get(i)))) {
exceltoPOJO.put(String.valueOf(i), POJOfields.get(top.get(i)));
}
}
/*處理Excel數(shù)據(jù)內(nèi)容*/
int endRowNum;
//獲取結(jié)束行數(shù)
if (EndRow == -1) {
endRowNum = sheet.getPhysicalNumberOfRows();
} else {
endRowNum = EndRow <= sheet.getPhysicalNumberOfRows() ? EndRow : sheet.getPhysicalNumberOfRows();
}
List<Map<String, Object>> mapList = new ArrayList<>();
//遍歷行數(shù)
for (int i = StatrRow - 1; i < endRowNum; i++) {
Row row = sheet.getRow(i);
if (null == row) {
continue;
}
//獲取需要的列數(shù)據(jù)
t texcel = (t) t.newInstance();
for (Map.Entry<String, Object> map : exceltoPOJO.entrySet()) {
//獲取Exceld對(duì)應(yīng)列的數(shù)據(jù)
String celldata = convertCellValueToString(row.getCell(Integer.parseInt(map.getKey())));
//使用發(fā)射
//獲取實(shí)體類T中指定成員變量的對(duì)象
PropertyDescriptor pd = new PropertyDescriptor((String) map.getValue(), texcel.getClass());
//獲取成員變量的set方法
Method method = pd.getWriteMethod();
//判斷成員變量的類型
Field field = texcel.getClass().getDeclaredField((String) map.getValue());
String object = field.getGenericType().getTypeName();
if (object.endsWith("String")) {
//執(zhí)行set方法
method.invoke(texcel, celldata);
}
if (object.endsWith("Double")) {
Double middata = Double.valueOf(celldata);
//執(zhí)行set方法
method.invoke(texcel, middata);
}
if (object.endsWith("Float")) {
Float middata = Float.valueOf(celldata);
//執(zhí)行set方法
method.invoke(texcel, middata);
}
if (object.endsWith("Integer")) {
Integer middata = Integer.parseInt(celldata);
//執(zhí)行set方法
method.invoke(texcel, middata);
}
}
result.add(texcel);
}
}
return result;
}
/**
* 獲取對(duì)應(yīng)的實(shí)體類成員
* */
private static Map<String, Object> getPOJOFieldAndValue(Class T) {
//聲明返回結(jié)果集
Map<String, Object> result = new HashMap<>();
Field[] fields = T.getDeclaredFields();//獲取屬性名
if (fields != null) {
for (Field field : fields) {
excelRescoure Rescoure = field.getAnnotation(excelRescoure.class);
if (Rescoure.value() != null && !"".equals(Rescoure.value())) {
result.put(Rescoure.value(), field.getName());
}
}
} else {
logger.warn("實(shí)體類:" + T + "不存在成員變量");
return null;
}
return result;
}
}
5.測(cè)試類
package com.cly.utils.Excel;
import java.util.*;
/**
* @author : CLy
* @ClassName : Readtest
* @date : 2020/7/9 16:31
**/
public class Readtest {
public static void main(String[] args) throws Exception {
/** 方法一
* fileName:Excel文件路徑
* StatrRow:讀取的開始行數(shù)(默認(rèn)填0)
* EndRow:讀取的結(jié)束行數(shù)(填-1為全部)
* ExistTop:是否存在頭部(如存在則讀取數(shù)據(jù)時(shí)會(huì)把頭部拼接到對(duì)應(yīng)數(shù)據(jù)作為KEY,若無(wú)則KEY為當(dāng)前列數(shù))
*/
List<Map<String,Object>> result =excelRead.ReadExcelByRC("D:.xls",2,10,false);
System.out.println(result.size());
System.out.println(result);
/**
* 方法二
* ReadExcelByPOJO(String fileName, int StatrRow, int EndRow, Class t)
* fileName:Excel文件路徑
* StatrRow:讀取的開始行數(shù)(默認(rèn)填0)
* EndRow:讀取的結(jié)束行數(shù)(填-1為全部)
* Class<T>:傳過(guò)來(lái)的實(shí)體類類型
*/
List<Object> result2 = excelRead.ReadExcelByPOJO("D:.xls",2,10,ExcelPOJO.class);
System.out.println(result2.size());
System.out.println(result2);
}
}
6.運(yùn)行結(jié)果和說(shuō)明
exce表格數(shù)據(jù)

方法一的運(yùn)行結(jié)果
1.ture:key為列名

2.false:key為第幾列列數(shù)

方法二的運(yùn)行結(jié)果
實(shí)體類的所有成員變量一定要加上自定義注釋@excelRescoure,不然會(huì)報(bào)錯(cuò)


還有很多不足的地方,請(qǐng)多多指點(diǎn),希望能給你帶來(lái)幫助。
SpringBoot實(shí)現(xiàn)內(nèi)存數(shù)據(jù)導(dǎo)出成Excel在另一篇文章 文章地址:http://www.dbjr.com.cn/article/202767.htm
總結(jié)
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)Excel讀取的文章就介紹到這了,更多相關(guān)SpringBoot實(shí)現(xiàn)Excel讀取內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中EasyExcel實(shí)現(xiàn)Excel文件的導(dǎo)入導(dǎo)出
- SpringBoot+easypoi實(shí)現(xiàn)數(shù)據(jù)的Excel導(dǎo)出
- SpringBoot整合EasyExcel實(shí)現(xiàn)文件導(dǎo)入導(dǎo)出
- SpringBoot集成EasyExcel實(shí)現(xiàn)Excel導(dǎo)入的方法
- SpringBoot內(nèi)存數(shù)據(jù)導(dǎo)出成Excel的實(shí)現(xiàn)方法
- 使用Springboot+poi上傳并處理百萬(wàn)級(jí)數(shù)據(jù)EXCEL
- 在SpringBoot: SpringBoot里面創(chuàng)建導(dǎo)出Excel的接口教程
- SpringBoot讀取excel表格的示例代碼
- 解決springboot 多線程使用MultipartFile讀取excel文件內(nèi)容報(bào)錯(cuò)問(wèn)題
- SpringBoot中使用JeecgBoot的Autopoi導(dǎo)出Excel的方法步驟
- SpringBoot整合POI導(dǎo)出通用Excel的方法示例
- Springboot POI導(dǎo)出Excel(瀏覽器)
- 基于SpringBoot框架管理Excel和PDF文件類型
- SpringBoot實(shí)現(xiàn)Excel文件批量上傳導(dǎo)入數(shù)據(jù)庫(kù)
- Springboot實(shí)現(xiàn)導(dǎo)入導(dǎo)出Excel的方法
相關(guān)文章
Spring Boot 2.x基礎(chǔ)教程之使用@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)的方法
在Spring Boot中編寫定時(shí)任務(wù)是非常簡(jiǎn)單的事,下面通過(guò)實(shí)例介紹如何在Spring Boot中創(chuàng)建定時(shí)任務(wù),實(shí)現(xiàn)每過(guò)5秒輸出一個(gè)當(dāng)前時(shí)間,感興趣的朋友跟隨小編一起看看吧2021-07-07
一文帶你學(xué)會(huì)Java網(wǎng)絡(luò)編程
網(wǎng)絡(luò)編程是指編寫運(yùn)行在多個(gè)設(shè)備(計(jì)算機(jī))的程序,這些設(shè)備都通過(guò)網(wǎng)絡(luò)連接起來(lái)。這篇文章將帶大家深入了解一下Java的網(wǎng)絡(luò)編程,需要的可以了解一下2022-08-08
java事件處理模型知識(shí)點(diǎn)總結(jié)
在本篇文章里小辮給大家分享的是一篇關(guān)于java事件處理模型知識(shí)點(diǎn)總結(jié)內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2021-01-01
Java多線程實(shí)現(xiàn)TCP網(wǎng)絡(luò)Socket編程(C/S通信)
這篇文章主要介紹了Java多線程實(shí)現(xiàn)TCP網(wǎng)絡(luò)Socket編程(C/S通信),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
Java并發(fā)編程之ConcurrentLinkedQueue源碼詳解
今天帶小伙伴們學(xué)習(xí)一下Java并發(fā)編程之Java ConcurrentLinkedQueue源碼,本篇文章詳細(xì)分析了ConcurrentLinkedQueue源碼,有代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助喲,需要的朋友可以參考下2021-05-05
application作用域?qū)崿F(xiàn)用戶登錄擠掉之前登錄用戶代碼
這篇文章主要介紹了application作用域?qū)崿F(xiàn)用戶登錄擠掉之前登錄用戶代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11

