--- x-spreadsheet

--- 文档 https://hondrytravis.com/x-spreadsheet-doc/

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="com.base.util.WebUtil"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; String id=WebUtil.getParam("id");
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>starting page</title> <meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<link href="<%=basePath%>x-spreadsheet/xspreadsheet.css" rel="stylesheet"></head>
<link rel="stylesheet" href="<%=basePath %>base/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="<%=basePath %>base/layuiadmin/style/admin.css" media="all"> </head> <body onload="load()">
<div style="position: fixed; right: 0; top: .3em;">
<input type="text" id="id" name="id" value="<%=id %>" lay-verify="required" autocomplete="off" class="layui-input" style="display: none;" >
<button id="save" name="save" class="layui-btn site-demo-active" data-type="sjglTabChange" lay-filter="demo" onclick="save()">保存</button>
</div>
<div id="x-spreadsheet-demo"></div>
</body>
<script src="<%=basePath %>base/layuiadmin/layui/layui.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script type="text/javascript" > function save(){ // 保存
const d = xs.getData();
//console.log(d[0]);
var merges = JSON.stringify(d[0].merges);
var rows = JSON.stringify(d[0].rows);
var styles = JSON.stringify(d[0].styles);
//console.log( merges);
//console.log( rows);
//console.log( styles);
var id = "<%=id%>";
$.ajax({
url:' ',
data:{merges:merges,rows:rows,styles:styles,id:id},
type:'post',
dataType: "json",
success:function(obj){
console.log("---");
//console.log(obj);            
}
});
} var htmlsourse = "";
var arr = "";
var excel_styles = "";
function getExcel(){
$.ajax({
url:' ',
type:'post',
dataType: "json",
async:false,
success:function(obj){
//console.log("---");  
//console.log(obj);
if(obj.length>0){
//rows={obj[0].htmlsourse};
htmlsourse = obj[0].excel_rows;
htmlsourse = $.parseJSON( htmlsourse ); //jQuery.parseJSON(jsonstr),可以将json字符串转换成json对象
//JSON.parse(jsonstr); //可以将json字符串转换成json对象
//console.log( htmlsourse);  
arr = obj[0].excel_merges
arr = arr.split(',');
//console.log( arr); 
excel_styles = obj[0].excel_styles;
excel_styles = excel_styles.replace(/\s+/g,""); // 去空格
excel_styles = $.parseJSON( excel_styles );
//console.log( excel_styles);
}        
}
});
}
var xs = "";
function load(){
console.log('---');
getExcel();
const rows = htmlsourse;
console.log('****');
/*const rows10 = { len: 1000 };
for (let i = 0; i < 1000; i += 1) {
rows10[i] = {
cells: {
0: { text: 'A-' + i },
1: { text: 'B-' + i },
2: { text: 'C-' + i },
3: { text: 'D-' + i },
4: { text: 'E-' + i },
5: { text: 'F-' + i },
}
};
}*/
//x_spreadsheet.locale('zh-cn');
var saveIcon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNTc3MTc3MDkyOTg4IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjI2NzgiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PC9zdHlsZT48L2RlZnM+PHBhdGggZD0iTTIxMy4zMzMzMzMgMTI4aDU5Ny4zMzMzMzRhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMSA4NS4zMzMzMzMgODUuMzMzMzMzdjU5Ny4zMzMzMzRhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMS04NS4zMzMzMzMgODUuMzMzMzMzSDIxMy4zMzMzMzNhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMS04NS4zMzMzMzMtODUuMzMzMzMzVjIxMy4zMzMzMzNhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMSA4NS4zMzMzMzMtODUuMzMzMzMzeiBtMzY2LjkzMzMzNCAxMjhoMzQuMTMzMzMzYTI1LjYgMjUuNiAwIDAgMSAyNS42IDI1LjZ2MTE5LjQ2NjY2N2EyNS42IDI1LjYgMCAwIDEtMjUuNiAyNS42aC0zNC4xMzMzMzNhMjUuNiAyNS42IDAgMCAxLTI1LjYtMjUuNlYyODEuNmEyNS42IDI1LjYgMCAwIDEgMjUuNi0yNS42ek0yMTMuMzMzMzMzIDIxMy4zMzMzMzN2NTk3LjMzMzMzNGg1OTcuMzMzMzM0VjIxMy4zMzMzMzNIMjEzLjMzMzMzM3ogbTEyOCAwdjI1NmgzNDEuMzMzMzM0VjIxMy4zMzMzMzNoODUuMzMzMzMzdjI5OC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMS00Mi42NjY2NjcgNDIuNjY2NjY3SDI5OC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMS00Mi42NjY2NjctNDIuNjY2NjY3VjIxMy4zMzMzMzNoODUuMzMzMzMzek0yNTYgMjEzLjMzMzMzM2g4NS4zMzMzMzMtODUuMzMzMzMzeiBtNDI2LjY2NjY2NyAwaDg1LjMzMzMzMy04NS4zMzMzMzN6IG0wIDU5Ny4zMzMzMzR2LTEyOEgzNDEuMzMzMzMzdjEyOEgyNTZ2LTE3MC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMSA0Mi42NjY2NjctNDIuNjY2NjY3aDQyNi42NjY2NjZhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMSA0Mi42NjY2NjcgNDIuNjY2NjY3djE3MC42NjY2NjdoLTg1LjMzMzMzM3ogbTg1LjMzMzMzMyAwaC04NS4zMzMzMzMgODUuMzMzMzMzek0zNDEuMzMzMzMzIDgxMC42NjY2NjdIMjU2aDg1LjMzMzMzM3oiIHAtaWQ9IjI2NzkiIGZpbGw9IiMyYzJjMmMiPjwvcGF0aD48L3N2Zz4='
var previewEl = document.createElement('img')
previewEl.src = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNjIxMzI4NTkxMjQzIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjU2NjMiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PGRlZnM+PHN0eWxlIHR5cGU9InRleHQvY3NzIj48L3N0eWxlPjwvZGVmcz48cGF0aCBkPSJNNTEyIDE4Ny45MDRhNDM1LjM5MiA0MzUuMzkyIDAgMCAwLTQxOC41NiAzMTUuNjQ4IDQzNS4zMjggNDM1LjMyOCAwIDAgMCA4MzcuMTIgMEE0MzUuNDU2IDQzNS40NTYgMCAwIDAgNTEyIDE4Ny45MDR6TTUxMiAzMjBhMTkyIDE5MiAwIDEgMSAwIDM4NCAxOTIgMTkyIDAgMCAxIDAtMzg0eiBtMCA3Ni44YTExNS4yIDExNS4yIDAgMSAwIDAgMjMwLjQgMTE1LjIgMTE1LjIgMCAwIDAgMC0yMzAuNHpNMTQuMDggNTAzLjQ4OEwxOC41NiA0ODUuNzZsNC44NjQtMTYuMzg0IDQuOTI4LTE0Ljg0OCA4LjA2NC0yMS41NjggNC4wMzItOS43OTIgNC43MzYtMTAuODggOS4zNDQtMTkuNDU2IDEwLjc1Mi0yMC4wOTYgMTIuNjA4LTIxLjMxMkE1MTEuNjE2IDUxMS42MTYgMCAwIDEgNTEyIDExMS4xMDRhNTExLjQ4OCA1MTEuNDg4IDAgMCAxIDQyNC41MTIgMjI1LjY2NGwxMC4yNCAxNS42OGMxMS45MDQgMTkuMiAyMi41OTIgMzkuMTA0IDMyIDU5Ljc3NmwxMC40OTYgMjQuOTYgNC44NjQgMTMuMTg0IDYuNCAxOC45NDQgNC40MTYgMTQuODQ4IDQuOTkyIDE5LjM5Mi0zLjIgMTIuODY0LTMuNTg0IDEyLjgtNi40IDIwLjA5Ni00LjQ4IDEyLjYwOC00Ljk5MiAxMi45MjhhNTExLjM2IDUxMS4zNiAwIDAgMS0xNy4yOCAzOC40bC0xMi4wMzIgMjIuNC0xMS45NjggMjAuMDk2QTUxMS41NTIgNTExLjU1MiAwIDAgMSA1MTIgODk2YTUxMS40ODggNTExLjQ4OCAwIDAgMS00MjQuNDQ4LTIyNS42bC0xMS4zMjgtMTcuNTM2YTUxMS4yMzIgNTExLjIzMiAwIDAgMS0xOS44NC0zNS4wMDhMNTMuMzc2IDYxMS44NGwtOC42NC0xOC4yNC0xMC4xMTItMjQuMTI4LTcuMTY4LTE5LjY0OC04LjMyLTI2LjYyNC0yLjYyNC05Ljc5Mi0yLjQ5Ni05LjkyeiIgcC1pZD0iNTY2NCI+PC9wYXRoPjwvc3ZnPg=='
previewEl.width = 16
previewEl.height = 16 xs = x_spreadsheet('#x-spreadsheet-demo', {
showToolbar: true,
showGrid: true,
showBottomBar: true,
extendToolbar: {
left: [
{
tip: 'Save',
icon: saveIcon,
onClick: (data, sheet) => {
console.log('click save button:', data, sheet)
}
}
],
right: [
{
tip: 'Preview',
el: previewEl,
onClick: (data, sheet) => {
console.log('click preview button:', data)
}
}
],
}
})
.loadData([{ // 加载数据
freeze: 'A1',
styles: excel_styles // 样式
/*{
bgcolor: '#f4f5f8',
textwrap: true,
color: '#900b09',
border: {
top: ['thin', '#0366d6'],
bottom: ['thin', '#0366d6'],
right: ['thin', '#0366d6'],
left: ['thin', '#0366d6'],
},
},{align: "center"}*/
,
merges: arr, // 合并单元格 位置
//["C3:D4", "G3:H4", "E4:F5", "B7:E9", "F7:H9", "B10:C11", "D10:E11"],
cols: { // 显示的个数
len: 50//, 2: { width: 200 },
},
rows, // 数据
},
// 多个 sheet
/*{ name: 'sheet-test', rows: rows10 }*/] ).change((cdata) => {
//console.log(cdata);
console.log('>>>', xs.getData());
}); xs.on('cell-selected', (cell, ri, ci) => {
console.log('selected>cell:', cell, ', ri:', ri, ', ci:', ci);
}).on('cell-edited', (text, ri, ci) => {
console.log('edited>text:', text, ', ri: ', ri, ', ci:', ci);
}); /*setTimeout(() => { // 隐藏 单元格
// xs.loadData([{ rows }]);
xs.cellText(14, 3, 'cell-text').reRender();
console.log('cell(8, 8):', xs.cell(8, 8));
console.log('cellStyle(8, 8):', xs.cellStyle(8, 8));
}, 5000);*/
} </script>
<script type="text/javascript" src="<%=basePath%>x-spreadsheet/xspreadsheet.js"></script>
</html>

---

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress; import net.sf.json.JSONObject; import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet; /**
*
* @author mysterious
*
*/ public class ExcelFinal { // 最终
// https://blog.csdn.net/lianzhang861/article/details/86234515
/**
* 获取单元格的值
* @param cell
* @return
*/
public static String getCellValue(Cell cell){ if(cell == null) {
cell.setCellType(Cell.CELL_TYPE_STRING);
return cell.getStringCellValue();
} if(cell.getCellType() == Cell.CELL_TYPE_STRING){ return cell.getStringCellValue(); }else if(cell.getCellType() == Cell.CELL_TYPE_BOOLEAN){ return String.valueOf(cell.getBooleanCellValue()); }else if(cell.getCellType() == Cell.CELL_TYPE_FORMULA){ return cell.getCellFormula() ; }else if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){ return String.valueOf(cell.getNumericCellValue()); }
return "";
} private static boolean is(HSSFSheet sheet,int i,int j) {
int MergeCount = sheet.getNumMergedRegions();
for(int l = 0 ; l < MergeCount ; l++){
CellRangeAddress ca = sheet.getMergedRegion(l);
String fa = ca.formatAsString() ;
//System.out.println(">>>"+fa);
int firstColumn = ca.getFirstColumn(); // 左上角的列号
int lastColumn = ca.getLastColumn(); // 右下角的列号
int firstRow = ca.getFirstRow(); // 左上角的行号
int lastRow = ca.getLastRow(); // 右下角的行号
//System.out.println("左上角的列号:"+firstColumn+",右下角的列号:"+lastColumn+",左上角的行号:"+firstRow+",右下角的行号:"+lastRow);
if(i >= firstRow && i <= lastRow){
if(j >= firstColumn && j <= lastColumn){
//Row fRow = sheet.getRow(firstRow);
//Cell fCell = fRow.getCell(firstColumn);
//System.out.println("此单元格在合并单元格内..."+getCellValue(fCell));
return true;
}
}
}
return false;
} private static String excel_styles = "[{\"border\":{\"bottom\":[\"thin\",\"#000\"],\"left\":[\"thin\",\"#000\"],\"right\":[\"thin\",\"#000\"],\"top\":[\"thin\",\"#000\"]}},{\"align\":\"center\"},{\"align\":\"center\",\"border\":{\"bottom\":[\"thin\",\"#000\"],\"left\":[\"thin\",\"#000\"],\"right\":[\"thin\",\"#000\"],\"top\":[\"thin\",\"#000\"]}}]"; public static Map<String, Object> readExcelToObj(String path) throws Exception {
File file = new File(path);
InputStream is = new FileInputStream(file);
HSSFWorkbook wb = new HSSFWorkbook(is);
Map<String, Object>map = new HashMap<String, Object>();
map = readExcel(wb);
map.put("excel_styles",excel_styles);
return map;
}
private static Map<String, Object> readExcel(HSSFWorkbook wb) {
Map<String, Object>map = new HashMap<String, Object>();
JSONObject rowJosn = new JSONObject(); // 行
//JSONObject cellsJosn = new JSONObject(); // cells
//JSONObject gridJson = new JSONObject(); // 格
//JSONObject gridValue = new JSONObject(); // 格数据
//int [] mergesArray = new int[2]; // 合并单元格
List<String> merges = new ArrayList<String>();// 合并单元格
String Emerges = ""; HSSFSheet sheet = wb.getSheetAt(0);
int trLength = sheet.getLastRowNum(); // 获取工作表上的最后一行
for(int i=0; i<trLength; i++) {
HSSFRow row = sheet.getRow(i);
int tdLength = row.getLastCellNum(); // 获取此行中最后一个单元格的索引加1 JSONObject cellsJosn = new JSONObject(); // cells
JSONObject gridJson = new JSONObject(); // 格
for(int j = 0;j<tdLength;j++) {
//得到Excel工作表指定行的单元格
HSSFCell c = row.getCell(j,row.CREATE_NULL_AS_BLANK);
//int cc = c.getColumnIndex();
//System.out.println("返回此单元格的列索引:"+cc);
System.out.println("行:"+i+",列"+j);
//---------------------------------------------boolean isMerge = is(sheet, i, j);
JSONObject gridValue = new JSONObject(); // 格数据
int [] mergesArray = new int[2]; // 合并单元格
if(isMerge) {
// "4":{ "cells":{ "1":{"text":"","merge":[0,21]} }
int MergeCount = sheet.getNumMergedRegions();
int lastColumn = 0;
for(int l = 0 ; l < MergeCount ; l++){
CellRangeAddress ca = sheet.getMergedRegion(l);
String fa = ca.formatAsString() ;
System.out.println(">>>"+fa);
int firstColumn = ca.getFirstColumn(); // 左上角的列号
lastColumn = ca.getLastColumn(); // 右下角的列号
int firstRow = ca.getFirstRow(); // 左上角的行号
int lastRow = ca.getLastRow(); // 右下角的行号
//System.out.println("左上角的列号:"+firstColumn+",右下角的列号:"+lastColumn+",左上角的行号:"+firstRow+",右下角的行号:"+lastRow);
if(i == firstRow) { // 表示新
if(j == firstColumn ){ // 表示新 // 表示 传入的 单元格 是符合的单元格
// 左上角的列号:1,右下角的列号:2,左上角的行号:4,右下角的行号:7
//添加列数据 ( 列:{text:‘数据’,merge[( 左下角行号 - h ),( -l)]} )
gridValue.put("text", c.getStringCellValue());
gridValue.put("style", 1);
mergesArray[0]=lastRow-firstRow; // 右上角列号 - 左上角列号
mergesArray[1]=lastColumn-firstColumn; // 右上角列号 - 左上角列号
gridValue.put("merge", mergesArray); merges.add(fa);
Emerges+=fa+",";
break;
}else{
if(j > firstColumn && j<= lastColumn){
//j = lastColumn; // 表示跳出 这一行 内符合 行号的 合并单元格 ,
break;
}else{// 一定是一个单独的 单元格 因为合并单元格也是 按着循序循环的
// 添加数据
}
} }else{ // 旧 // 表示 这次的 合并单元格 于此次传入的 单元格不在一个位置
// 判断是否是一列的 合并单元格
if(i > firstRow && i<= lastRow){ // 表示 该行 存在合并单元格
if(j >= firstColumn && j<= lastColumn){ // 是否 为当前遍历出来的 单元格内
//j = lastColumn; // 表示跳出 这一行 内符合 行号的 合并单元格 ,
break;
}else{// 一定是一个单独的 单元格 因为合并单元格也是 按着循序循环的
// 添加数据
}
}
}
}
gridJson.put(j, gridValue); // 放入格内
j = lastColumn; // 表示跳出 这一行 内符合 行号的 合并单元格 ,
}else{
c.setCellType(Cell.CELL_TYPE_STRING);
gridValue.put("text", c.getStringCellValue());
gridValue.put("style", 1);
gridJson.put(j, gridValue); // 放入格内
}
}
cellsJosn.put("cells", gridJson);
rowJosn.put(i, cellsJosn); }
System.out.println(">>>"+rowJosn);
System.out.println(">>>"+merges.toString());
map.put("excel_rows", rowJosn);
//map.put("excel_merges", merges);
Emerges = Emerges.substring(0, Emerges.length()-1);
map.put("excel_merges", Emerges);
return map;
} public static void main(String[] args) {
// TODO Auto-generated method stub // mysterious
try {
String widz = "D:\\Book1.xls";
readExcelToObj(widz);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }

---

/*左下角的行号 = 右下角的行号
左下角的列号 = 左上角的列号
右上角的行号 = 左上角的行号
右上角的列号 = 右下角的列号*/ int firstColumn = ca.getFirstColumn(); // 左上角的列号
int lastColumn = ca.getLastColumn(); // 右下角的列号
int firstRow = ca.getFirstRow(); // 左上角的行号
int lastRow = ca.getLastRow(); // 右下角的行号
a(s,h,l){ // sheet,行,列
if(h = 左上角的行号) { // 表示新
//if(){// 当前行是否已经有数据存在 一格一格遍历无需判断是否存在 //--- 添加行数据 ( 行:{cells: { ) }
if(l = 左上角的列号 ){ // 表示新 // 表示 传入的 单元格 是符合的单元格
// 左上角的列号:1,右下角的列号:2,左上角的行号:4,右下角的行号:7
添加列数据 ( 列:{text:‘数据’,merge[( 左下角行号 - h ),( -l)]} )
}else{
if(l > 左上角的列号 && l<= 右上角的列号){
l = 右上角的列号+1; // 表示跳出 这一行 内符合 行号的 合并单元格 ,
return l;
}else{// 一定是一个单独的 单元格 因为合并单元格也是 按着循序循环的
// 添加数据
}
} }esle{ // 旧 // 表示 这次的 合并单元格 于此次传入的 单元格不在一个位置
// 判断是否是一列的 合并单元格
if(h > 左上角的行号 && h<= 左下角的行号){ // 表示 该行 存在合并单元格
if(l ){ // 是否 为当前遍历出来的 单元格内
l = 右上角的列号+1; // 表示跳出 这一行 内符合 行号的 合并单元格 ,
}else{// 一定是一个单独的 单元格 因为合并单元格也是 按着循序循环的
// 添加数据
}
}
}
}

--- 多页---------------------------------------------------------------------------------------------------------------------------

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="com.base.util.WebUtil"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; String id=WebUtil.getParam("id");
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>starting page</title> <meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<link href="<%=basePath%>x-spreadsheet/xspreadsheet.css" rel="stylesheet"></head>
<link rel="stylesheet" href="<%=basePath %>base/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="<%=basePath %>base/layuiadmin/style/admin.css" media="all"> </head> <body onload="load()">
<div style="position: fixed; right: 0; top: .3em;">
<input type="text" id="id" name="id" value="<%=id %>" lay-verify="required" autocomplete="off" class="layui-input" style="display: none;" >
<button id="save" name="save" class="layui-btn site-demo-active" data-type="sjglTabChange" lay-filter="demo" onclick="save()">保存</button>
</div>
<div id="x-spreadsheet-demo"></div>
</body>
<script src="<%=basePath %>base/layuiadmin/layui/layui.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script type="text/javascript" > function save(){
const d = xs.getData();
console.log(d[0]);
var merges = JSON.stringify(d[0].merges);
var rows = JSON.stringify(d[0].rows);
var styles = JSON.stringify(d[0].styles);
var id = "<%=id%>";
$.ajax({
url:'<%=basePath%>gzlc/saveExcel.do',
data:{merges:merges,rows:rows,styles:styles,id:id},
type:'post',
dataType: "json",
success:function(obj){
console.log("---");
console.log(obj);            
}
});
} var excel_styles = "";
var mycars=new Array();
function getExcel(){
$.ajax({
url:'<%=basePath%>gzlc/getExcel.do?id=<%=id%>',
type:'post',
dataType: "json",
async:false,
success:function(obj){
console.log("---");  
//console.log(obj);
if(obj.length>0){
excel_styles = obj[0].excel_styles;
excel_styles = $.parseJSON( excel_styles );
//console.log( excel_styles);
var htmlsourse = obj[0].excel_rows;
console.log("-*-------------------------------------------------------");
htmlsourse = $.parseJSON( htmlsourse );
console.log( htmlsourse); var i = 0;
$.each(htmlsourse, function(j) {
var xx = htmlsourse[j];
console.log(htmlsourse[j]);
//console.log(j);
var person = {
freeze : ""+j,
styles : excel_styles,
merges:j,
cols: {len: 50}, // 显示的个数
rows:j
};
var excel_rows = xx.excel_rows;
var excel_merges = xx.excel_merges;
excel_merges = excel_merges.replace(/\s+/g,""); // 去空格
excel_merges = excel_merges.split(',');
//console.log(excel_rows);
//console.log(excel_merges);
//console.log("////////////////////");
//console.log(i);
person.merges = excel_merges;
person.rows = excel_rows;
mycars[i]=person;
i++;
});
console.log(mycars);
}
}
});
}
var xs = "";
function load(){
console.log('---');
getExcel();
console.log('****');
//x_spreadsheet.locale('zh-cn');
var saveIcon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNTc3MTc3MDkyOTg4IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjI2NzgiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PC9zdHlsZT48L2RlZnM+PHBhdGggZD0iTTIxMy4zMzMzMzMgMTI4aDU5Ny4zMzMzMzRhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMSA4NS4zMzMzMzMgODUuMzMzMzMzdjU5Ny4zMzMzMzRhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMS04NS4zMzMzMzMgODUuMzMzMzMzSDIxMy4zMzMzMzNhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMS04NS4zMzMzMzMtODUuMzMzMzMzVjIxMy4zMzMzMzNhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMSA4NS4zMzMzMzMtODUuMzMzMzMzeiBtMzY2LjkzMzMzNCAxMjhoMzQuMTMzMzMzYTI1LjYgMjUuNiAwIDAgMSAyNS42IDI1LjZ2MTE5LjQ2NjY2N2EyNS42IDI1LjYgMCAwIDEtMjUuNiAyNS42aC0zNC4xMzMzMzNhMjUuNiAyNS42IDAgMCAxLTI1LjYtMjUuNlYyODEuNmEyNS42IDI1LjYgMCAwIDEgMjUuNi0yNS42ek0yMTMuMzMzMzMzIDIxMy4zMzMzMzN2NTk3LjMzMzMzNGg1OTcuMzMzMzM0VjIxMy4zMzMzMzNIMjEzLjMzMzMzM3ogbTEyOCAwdjI1NmgzNDEuMzMzMzM0VjIxMy4zMzMzMzNoODUuMzMzMzMzdjI5OC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMS00Mi42NjY2NjcgNDIuNjY2NjY3SDI5OC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMS00Mi42NjY2NjctNDIuNjY2NjY3VjIxMy4zMzMzMzNoODUuMzMzMzMzek0yNTYgMjEzLjMzMzMzM2g4NS4zMzMzMzMtODUuMzMzMzMzeiBtNDI2LjY2NjY2NyAwaDg1LjMzMzMzMy04NS4zMzMzMzN6IG0wIDU5Ny4zMzMzMzR2LTEyOEgzNDEuMzMzMzMzdjEyOEgyNTZ2LTE3MC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMSA0Mi42NjY2NjctNDIuNjY2NjY3aDQyNi42NjY2NjZhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMSA0Mi42NjY2NjcgNDIuNjY2NjY3djE3MC42NjY2NjdoLTg1LjMzMzMzM3ogbTg1LjMzMzMzMyAwaC04NS4zMzMzMzMgODUuMzMzMzMzek0zNDEuMzMzMzMzIDgxMC42NjY2NjdIMjU2aDg1LjMzMzMzM3oiIHAtaWQ9IjI2NzkiIGZpbGw9IiMyYzJjMmMiPjwvcGF0aD48L3N2Zz4='
var previewEl = document.createElement('img')
previewEl.src = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNjIxMzI4NTkxMjQzIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjU2NjMiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PGRlZnM+PHN0eWxlIHR5cGU9InRleHQvY3NzIj48L3N0eWxlPjwvZGVmcz48cGF0aCBkPSJNNTEyIDE4Ny45MDRhNDM1LjM5MiA0MzUuMzkyIDAgMCAwLTQxOC41NiAzMTUuNjQ4IDQzNS4zMjggNDM1LjMyOCAwIDAgMCA4MzcuMTIgMEE0MzUuNDU2IDQzNS40NTYgMCAwIDAgNTEyIDE4Ny45MDR6TTUxMiAzMjBhMTkyIDE5MiAwIDEgMSAwIDM4NCAxOTIgMTkyIDAgMCAxIDAtMzg0eiBtMCA3Ni44YTExNS4yIDExNS4yIDAgMSAwIDAgMjMwLjQgMTE1LjIgMTE1LjIgMCAwIDAgMC0yMzAuNHpNMTQuMDggNTAzLjQ4OEwxOC41NiA0ODUuNzZsNC44NjQtMTYuMzg0IDQuOTI4LTE0Ljg0OCA4LjA2NC0yMS41NjggNC4wMzItOS43OTIgNC43MzYtMTAuODggOS4zNDQtMTkuNDU2IDEwLjc1Mi0yMC4wOTYgMTIuNjA4LTIxLjMxMkE1MTEuNjE2IDUxMS42MTYgMCAwIDEgNTEyIDExMS4xMDRhNTExLjQ4OCA1MTEuNDg4IDAgMCAxIDQyNC41MTIgMjI1LjY2NGwxMC4yNCAxNS42OGMxMS45MDQgMTkuMiAyMi41OTIgMzkuMTA0IDMyIDU5Ljc3NmwxMC40OTYgMjQuOTYgNC44NjQgMTMuMTg0IDYuNCAxOC45NDQgNC40MTYgMTQuODQ4IDQuOTkyIDE5LjM5Mi0zLjIgMTIuODY0LTMuNTg0IDEyLjgtNi40IDIwLjA5Ni00LjQ4IDEyLjYwOC00Ljk5MiAxMi45MjhhNTExLjM2IDUxMS4zNiAwIDAgMS0xNy4yOCAzOC40bC0xMi4wMzIgMjIuNC0xMS45NjggMjAuMDk2QTUxMS41NTIgNTExLjU1MiAwIDAgMSA1MTIgODk2YTUxMS40ODggNTExLjQ4OCAwIDAgMS00MjQuNDQ4LTIyNS42bC0xMS4zMjgtMTcuNTM2YTUxMS4yMzIgNTExLjIzMiAwIDAgMS0xOS44NC0zNS4wMDhMNTMuMzc2IDYxMS44NGwtOC42NC0xOC4yNC0xMC4xMTItMjQuMTI4LTcuMTY4LTE5LjY0OC04LjMyLTI2LjYyNC0yLjYyNC05Ljc5Mi0yLjQ5Ni05LjkyeiIgcC1pZD0iNTY2NCI+PC9wYXRoPjwvc3ZnPg=='
previewEl.width = 16
previewEl.height = 16 xs = x_spreadsheet('#x-spreadsheet-demo', {
showToolbar: true,
showGrid: true,
showBottomBar: true,
extendToolbar: {
left: [ { tip: 'Save', icon: saveIcon,
onClick: (data, sheet) => {
console.log('click save button:', data, sheet)
}
} ],
right: [ { tip: 'Preview', el: previewEl,
onClick: (data, sheet) => {
console.log('click preview button:', data)
}
} ],
}
});
xs.loadData(mycars).change((cdata) => {
console.log(cdata);
console.log('>>>', xs.getData());
}); xs.on('cell-selected', (cell, ri, ci) => {
console.log('selected>cell:', cell, ', ri:', ri, ', ci:', ci);
}).on('cell-edited', (text, ri, ci) => {
console.log('edited>text:', text, ', ri: ', ri, ', ci:', ci);
});
} </script>
<script type="text/javascript" src="<%=basePath%>x-spreadsheet/xspreadsheet.js"></script>
</html>

---

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; 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.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress; import net.sf.json.JSONObject; /**
*
* @author mysterious
*
*/ public class ExcelFinal { // 最终
// https://blog.csdn.net/lianzhang861/article/details/86234515
private static Workbook wb;
private static String excel_styles = "[{\"border\":{\"bottom\":[\"thin\",\"#000\"],\"left\":[\"thin\",\"#000\"],\"right\":[\"thin\",\"#000\"],\"top\":[\"thin\",\"#000\"]}},{\"align\":\"center\"},{\"align\":\"center\",\"border\":{\"bottom\":[\"thin\",\"#000\"],\"left\":[\"thin\",\"#000\"],\"right\":[\"thin\",\"#000\"],\"top\":[\"thin\",\"#000\"]}}]"; /**
* 获取单元格的值
* @param cell
* @return
*/
public static String getCellValue(Cell cell){ if(cell == null) {
cell.setCellType(Cell.CELL_TYPE_STRING);
return cell.getStringCellValue();
} if(cell.getCellType() == Cell.CELL_TYPE_STRING){ return cell.getStringCellValue(); }else if(cell.getCellType() == Cell.CELL_TYPE_BOOLEAN){ return String.valueOf(cell.getBooleanCellValue()); }else if(cell.getCellType() == Cell.CELL_TYPE_FORMULA){ return cell.getCellFormula() ; }else if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){ return String.valueOf(cell.getNumericCellValue()); }
return "";
} private static boolean is(Sheet sheet,int i,int j) {
int MergeCount = sheet.getNumMergedRegions();
for(int l = 0 ; l < MergeCount ; l++){
CellRangeAddress ca = sheet.getMergedRegion(l);
String fa = ca.formatAsString() ;
//System.out.println(">>>"+fa);
int firstColumn = ca.getFirstColumn(); // 左上角的列号
int lastColumn = ca.getLastColumn(); // 右下角的列号
int firstRow = ca.getFirstRow(); // 左上角的行号
int lastRow = ca.getLastRow(); // 右下角的行号
//System.out.println("左上角的列号:"+firstColumn+",右下角的列号:"+lastColumn+",左上角的行号:"+firstRow+",右下角的行号:"+lastRow);
if(i >= firstRow && i <= lastRow){
if(j >= firstColumn && j <= lastColumn){
//Row fRow = sheet.getRow(firstRow);
//Cell fCell = fRow.getCell(firstColumn);
System.out.println("此单元格在合并单元格内...");
return true;
}
}
}
return false;
} private static Map<String, Object> readExcel(Workbook wb) {
Map<String, Object>map = new HashMap<String, Object>();
JSONObject JO = new JSONObject(); int sheetCount = wb.getNumberOfSheets(); //Sheet的数量
for(int s = 0;s<sheetCount;s++) {
JSONObject sheetMap = new JSONObject(); // 第二页时
Sheet sheet = wb.getSheetAt(s);
String sheetName = sheet.getSheetName();
int trLength = sheet.getLastRowNum(); // 获取工作表上的最后一行
JSONObject rowJosn = new JSONObject(); // 行
String Emerges = "";// 合并单元格 for(int i=0; i<trLength; i++) {
Row row = sheet.getRow(i);
int tdLength = row.getLastCellNum(); // 获取此行中最后一个单元格的索引加1
JSONObject cellsJosn = new JSONObject(); // cells
JSONObject gridJson = new JSONObject(); // 格 for(int j = 0;j<tdLength;j++) {
Cell c = row.getCell(j,row.CREATE_NULL_AS_BLANK);
System.out.println("sheet:"+s+",行:"+i+",列"+j); boolean isMerge = is(sheet, i, j);
JSONObject gridValue = new JSONObject(); // 格数据
int [] mergesArray = new int[2]; // 合并单元格
if(isMerge) {
int MergeCount = sheet.getNumMergedRegions();
int lastColumn = 0;
for(int l = 0 ; l < MergeCount ; l++){
CellRangeAddress ca = sheet.getMergedRegion(l);
String fa = ca.formatAsString() ;
System.out.println(">>>"+fa);
int firstColumn = ca.getFirstColumn(); // 左上角的列号
lastColumn = ca.getLastColumn(); // 右下角的列号
int firstRow = ca.getFirstRow(); // 左上角的行号
int lastRow = ca.getLastRow(); // 右下角的行号
System.out.println("左上角的列号:"+firstColumn+",右下角的列号:"+lastColumn+",左上角的行号:"+firstRow+",右下角的行号:"+lastRow);
if(i == firstRow) { // 表示新
if(j == firstColumn ){ // 表示新 // 表示 传入的 单元格 是符合的单元格
// 左上角的列号:1,右下角的列号:2,左上角的行号:4,右下角的行号:7
//添加列数据 ( 列:{text:‘数据’,merge[( 左下角行号 - h ),( -l)]} )
gridValue.put("text", c.getStringCellValue());
gridValue.put("style", 1);
mergesArray[0]=lastRow-firstRow; // 右上角列号 - 左上角列号
mergesArray[1]=lastColumn-firstColumn; // 右上角列号 - 左上角列号
gridValue.put("merge", mergesArray); Emerges+=fa+",";
break;
}else{
if(j > firstColumn && j<= lastColumn){
//j = lastColumn; // 表示跳出 这一行 内符合 行号的 合并单元格 ,
break;
}else{// 一定是一个单独的 单元格 因为合并单元格也是 按着循序循环的
// 添加数据
}
} }else{ // 旧 // 表示 这次的 合并单元格 于此次传入的 单元格不在一个位置
// 判断是否是一列的 合并单元格
if(i > firstRow && i<= lastRow){ // 表示 该行 存在合并单元格
if(j >= firstColumn && j<= lastColumn){ // 是否 为当前遍历出来的 单元格内
//j = lastColumn; // 表示跳出 这一行 内符合 行号的 合并单元格 ,
break;
}else{// 一定是一个单独的 单元格 因为合并单元格也是 按着循序循环的
// 添加数据
}
}
}
}
gridJson.put(j, gridValue); // 放入格内
j = lastColumn; // 表示跳出 这一行 内符合 行号的 合并单元格 ,
}else{
c.setCellType(Cell.CELL_TYPE_STRING);
gridValue.put("text", c.getStringCellValue());
gridValue.put("style", 1);
gridJson.put(j, gridValue); // 放入格内
}
} cellsJosn.put("cells", gridJson);
rowJosn.put(i, cellsJosn);
}
sheetMap.put("excel_rows", rowJosn);
Emerges = Emerges.substring(0, Emerges.length()-1);
sheetMap.put("excel_merges", Emerges);
JO.put(sheetName, sheetMap);
//map.put(sheetName, sheetMap);
}
System.out.println(">>>"+JO);
map.put("excel_rows", JO);
map.put("excel_styles", excel_styles);
return map;
}
public static Map<String, Object> readExcelToObj(String path) throws Exception {
// 获得文件所在地
File file = new File(path); List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
FileInputStream is = new FileInputStream(file); //文件流
wb = WorkbookFactory.create(is); //这种方式 Excel 2003/2007/2010 都是可以处理的
return readExcel(wb); } public static void main(String[] args) {
// TODO Auto-generated method stub
String path = "设计交底记录.xls"; // 文件在服务器的地址
try {
readExcelToObj(path);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }

--- mysterious

java web 在线编辑Excel -- x-spreadsheet的更多相关文章

  1. handsontable在线编辑excel扩展功能-踩坑篇

    简述 先说一下背景,之所以封装handsontable插件,是因为公司要实现在线编辑导入excel文件的功能,然后我就找到了这个功能强大的插件handsontable. 具体功能 除了handsont ...

  2. java web 在线聊天的基本实现

    随着互联网的发展,http的协议有些时候不能满足需求,比如在现聊天的实现.如果使用http协议必须轮训,或者使用长链接.必须要一个request,这样后台才能发送信息到前端. 后台不能主动找客户端通信 ...

  3. [转载] Java开发在线编辑Word同时实现全文检索

    一.背景介绍 Word文档与日常办公密不可分,在实际应用中,当某一文档服务器中有很多Word文档,假如有成千上万个文档时,用户查找打开包含某些指定关键字的文档就变得很困难,一般情况下能想到的解决方案是 ...

  4. [原创]Java开发在线编辑Word同时实现全文检索

    一.背景介绍 Word文档与日常办公密不可分,在实际应用中,当某一文档服务器中有很多Word文档,假如有成千上万个文档时,用户查找打开包含某些指定关键字的文档就变得很困难,一般情况下能想到的解决方案是 ...

  5. Java web的读取Excel简单Demo

    目录结构: Data.xls数据:   后台页面: GetExcelData.java       public void doGet(HttpServletRequest request, Http ...

  6. java web实现在线编辑word,并将word导出(一)

    前段时间领导交代了一个需求:客户需要一个能够web在线编辑文字,如同编辑word文档一样,同时能够将编辑完成的内容导出为word文档并下载到本地. 我们选择了前台使用富文本插件的形式用于编辑内容,使用 ...

  7. java 网站源码 在线编辑模版 代码编辑器 兼容手机平板PC freemaker 静态引擎

    前台: 支持四套模版, 可以在后台切换   系统介绍: 1.网站后台采用主流的 SSM 框架 jsp JSTL,网站后台采用freemaker静态化模版引擎生成html 2.因为是生成的html,所以 ...

  8. Atitit.office word  excel  ppt pdf 的web在线预览方案与html转换方案 attilax 总结

    Atitit.office word  excel  ppt pdf 的web在线预览方案与html转换方案 attilax 总结 1. office word  excel pdf 的web预览要求 ...

  9. Office word excel电子表格在线编辑的实现方法

    Office xp之后的版本支持通过webdav协议(http的扩展)直接编辑服务器上的文件. IIS(6.0)支持webdav,这在IIS管理器的web服务扩展中可以看到.利用IIS作为webdav ...

随机推荐

  1. Vue插槽slot理解与初体验 ~

    一.插槽的理解 1.官网介绍 Vue 实现了一套内容分发的 API,将 <slot> 元素作为承载分发内容的出口. 2.为什么使用插槽 Vue 中有一个重要的概念-组件,可以在开发中将子组 ...

  2. Win32窗口框架

    Win32窗口框架 WindowClass 单例,负责窗口初始化注册和取消注册: 负责提供静态方法: 放在Window类内部,方便初始化时,wndProc(HandleMsgSetup)的赋值: cl ...

  3. Java中JDK、JRE和JVM三者之间有什么区别和联系?Java基础!

    任何语言或软件都需要一个运行环境.正如人想生活在空气中,鱼想生活在水中一样,喜荫植物不能暴露在阳光下,任何物体个体的存在都离不开其所需的环境,编程语言也是一样的. 接下来就详细描述一下Java中JDK ...

  4. Spatial Analyst 工具-数学分析

    数学分析 # Process: Abs arcpy.gp.Abs_sa("", 输出栅格) # Process: Exp arcpy.gp.Exp_sa("", ...

  5. Java(31)泛型和可变参数

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15228443.html 博客主页:https://www.cnblogs.com/testero ...

  6. iostream 操作符

    iostream 操作符 Input/output manipulators - cppreference.com

  7. Java中的函数式编程(七)流Stream的Map-Reduce操作

    写在前面 Stream 的 Map-Reduce 操作是Java 函数式编程的精华所在,同时也是最为复杂的部分.但一旦你啃下了这块硬骨头,那你就真正熟悉Java的函数式编程了. 如果你有大数据的编程经 ...

  8. Redis:学习笔记-01

    Redis:学习笔记-01 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 1. Redis入门 2.1 ...

  9. [Beta]the Agiles Scrum Meeting 9

    会议时间:2020.5.24 21:00 1.每个人的工作 今天已完成的工作 成员 已完成的工作 issue yjy 撰写技术博客 tq 实现评测机获取评测状态功能 评测部分增加更多评测指标 wjx ...

  10. Beta阶段第二次会议

    时间:2020.5.18 工作进展 姓名 工作 难度 完成度 ltx 1.在开小程序开发文档,学习相关知识 轻 85% xyq 1.完成活动场地申请可视化代码(耗时半天) 中 100% lm 1.设计 ...