需求.提供公共的可以按照一定条件查询出结果,并提供将查询结果全部下载功能(Excel、CSV、TXT),由于一次性查出结果放到内存会占用大量内存.需要支持分页模式查询出所有数据。

实现思路

  1.在公共的controller(BaseController)中增加下载方法

  2.支持自定义分页查询方式、自定义表头和查询结果属性对应

  

@ResponseBody
@RequestMapping("/exportExcel.json")
public void exportExcel(HttpServletRequest request, HttpServletResponse response, final DeductCurrentsQry qry) throws Exception { // 从零行开始导出
qry.setStart(0);
// 分页设置大一点,提高导出效率
qry.setLimit(50);
//开始导出数据
DownloadDataLoader<DeductCurrentVo> loader = new DownloadDataLoader<DeductCurrentVo>() {
@Override
protected List<DeductCurrentVo> getDownloadData(Integer pageNum) {
// pageNum 初始值为0,在下载工具类中,通过对pageNum的自加,达到分页查询效果
qry.setStart(pageNum * qry.getLimit());
PageDataList<DeductCurrentVo> pageBean = getPageDataList(qry);
return pageBean.getRows();
}
};
String[] hearders = new String[] {"客户ID", "抵用券编号", "抵用券类型", "起投限制", "抵用券面值", "投资金额", "产品代码", "抵用券状态", "抵用券兑换码", "发放时间", "使用时间" };
String[] fields = new String[] { "customerId", "id", "deductType", "minInvestAmount", "faceValueFormat", "investAmount", "productCode", "deductStatus", "deductSn", "createDatetimeFormat", "usedDatetimeFormat" }; this.download(response,String.format("抵用券记录_%S.xls", DateUtil.dateStr(new Date())),
Arrays.asList(hearders), null, loader, Arrays.asList(fields));
}
package com.wjs.common.web;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.httpclient.util.DateUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import com.wjs.common.util.StringEscapeEditor;
import com.wjs.common.util.excel.ExcelUtils; /**
* 基础控制器
*
* 其他控制器继承此控制器获得日期字段类型转换和防止XSS攻击的功能
*
* @author Moon
*
*/
@Controller
public class BaseController { private static final Logger LOGGER = LoggerFactory.getLogger(BaseController.class); @InitBinder
public void initBinder(ServletRequestDataBinder binder) { /**
* 自动转换日期类型的字段格式
*/
// binder.registerCustomEditor(Date.class, new CustomDateEditor(
// new SimpleDateFormat("yyyy-MM-dd"), true)); /**
* 防止XSS攻击
*/
binder.registerCustomEditor(String.class, new StringEscapeEditor(true, false));
} /**
* http请求成功时调用
*
* @return
*
* @author chenchunhui
*/
protected <T> JsonResult<T> success() { return this.success("操作成功", null);
} /**
* http请求成功时调用
*
* @param data
* 返回给前台的数据
* @return 返回给前台的标准json对象
*/
protected <T> JsonResult<T> success(T data) { return this.success("操作成功", data);
} /**
* http请求成功时调用
*
* @param msg
* 信息说明
* @param data
* 返回给前端的数据
* @param <T>
* @return 返回给前台的标准json对象
*
* @author chenchunhui
*/
protected <T> JsonResult<T> success(String msg, T data) { JsonResult<T> result = new JsonResult<T>(JsonResult.Status.SUCCESS, msg, data);
if (LOGGER.isDebugEnabled()) {
String logString = result.toString();
if (logString.length() > 1024) {
logString = logString.substring(0, 1024);
}
LOGGER.debug(logString);
}
return result;
} /**
* http请求失败时调用
*
* @return 返回给前台的标准json对象
*
* @author chenchunhui
*/
protected <T> JsonResult<T> error() { return this.error("系统错误");
} /**
* http请求失败时调用
*
* @param msg
* 信息说明
* @return 返回给前台的标准json对象
*
* @author chenchunhui
*/
protected <T> JsonResult<T> error(String msg) { JsonResult<T> result = new JsonResult<T>(JsonResult.Status.ERROR, msg);
if (LOGGER.isInfoEnabled()) {
String logString = result.toString();
if (logString.length() > 1024) {
logString = logString.substring(0, 1024);
}
LOGGER.info(logString);
}
return result;
} /**
* 分页下载数据获取类
* @author Silver
* @date 2017年3月16日 上午11:45:13
*
* @param <T>
*
*/
protected abstract class DownloadDataLoader<T> { /**
* 分页下载属性值控制操作类
* @param bean
* @param propertyName
* @param property
* @return
* @author Silver
* @date 2017年3月16日 上午11:45:45
*/
protected String convertProperty(T bean, String propertyName, Object property) {
return property == null ? "" : property.toString();
} /**
* 分页下载属性赋值
* @param bean
* @param propertyName
* @return
* @author Silver
* @date 2017年3月16日 上午11:46:37
*/
protected Object getProperty(T bean, String propertyName) {
try {
return BeanUtils.getProperty(bean, propertyName);
} catch (Throwable e) {
LOGGER.info("bean:" + bean + ",Property:" + propertyName + e.getMessage(), e);
return null;
}
} /**
* 数据获取接口
* @param pageNum -- 从0计数
* @return
* @throws Exception
* @author Silver
* @date 2017年3月16日 上午11:47:07
*/
protected abstract List<T> getDownloadData(Integer pageNum) throws Exception;
}; protected static interface Writer {
public void write(Collection<String> row) throws IOException;
} /**
* Web下载文件
* @param response httpResponse信息
* @param fileName 文件名称,如果文件名称为空的情况默认【 日期.csv】格式
* @param header 表头名称
* @param columnWidth 列宽
* @param loader 数据加载类
* @param queryParam 如果有查询条件的传递
* @param propertyNames
* @throws Exception
* @author Silver
* @date 2017年3月16日 上午11:47:31
*/
protected <T> void download(HttpServletResponse response, String fileName, List<String> header, List<Integer> columnWidth, DownloadDataLoader<T> loader, List<String> propertyNames) throws Exception { if (StringUtils.isEmpty(fileName) || loader == null || CollectionUtils.isEmpty(propertyNames)) {
throw new RuntimeException("参数错误。FileName:" + fileName + ",DataLoader:" + loader + ",PropertyName:" + propertyNames);
}
// 获取输出流,设置content-type等头域
final OutputStream out = getResponseStream(response ,fileName);
try {
Writer writer = null;
// 获取文件后缀名
String extension = FilenameUtils.getExtension(fileName);
// 如果是excel的后缀
if ("xls".equalsIgnoreCase(extension) || "xlsx".equalsIgnoreCase(extension)) {
Workbook workbook = new HSSFWorkbook();
Sheet sheet = workbook.createSheet("sheet1");
final List<Collection<String>> rows = new ArrayList<Collection<String>>();
writer = new Writer() {
@Override
public void write(Collection<String> row) {
rows.add(row);
}
}; writeOutputStream(loader, propertyNames, writer);
// 写入excel
if (!ExcelUtils.setExcelInfo(sheet, columnWidth, header, rows)) {
throw new IOException("设置导出文件内容失败。");
} workbook.write(out);
} else if("csv".equalsIgnoreCase(extension)) {
writer = new Writer() { @Override
public void write(Collection<String> row) throws IOException { String str = ExcelUtils.collectionToCsvString(row);
byte[] content = org.apache.commons.codec.binary.StringUtils.getBytesUnchecked(str + "\n",
"GBK");
IOUtils.write(content, out);
out.flush();
}
};
// 写文件头
writer.write(header);
// 写文件
writeOutputStream(loader, propertyNames, writer);
}else{
writer = new Writer() { @Override
public void write(Collection<String> row) throws IOException { IOUtils.write(org.apache.commons.codec.binary.StringUtils.getBytesUnchecked(row + "\n",
"GBK"), out);
out.flush();
}
};
// 写文件头
writer.write(header);
// 写文件
writeOutputStream(loader, propertyNames, writer);
}
out.flush();
} finally {
IOUtils.closeQuietly(out);
}
} /**
* 获得输出流
*
* @return
* @throws IOException
*/
protected OutputStream getResponseStream(HttpServletResponse response, String fileName) throws IOException {
if (StringUtils.isEmpty(fileName)) {
fileName = DateUtil.formatDate(new Date(), "yyyy-MM-dd_HH-mm-ss") + ".csv";
}
response.reset(); String extension = FilenameUtils.getExtension(fileName);
if("xlsx".equalsIgnoreCase(extension)){
// 部分window版本生成后的xlsx打不开,默认改成xls打开
fileName = fileName.substring(0, fileName.length() -1);
}
//设置响应编码
response.setCharacterEncoding("UTF-8");
//设置对应的contentType
response.setContentType("application/x-download;charset=UTF-8");
// response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename="
+ new String(fileName.getBytes("gb2312"), "ISO-8859-1"));
OutputStream out = response.getOutputStream(); return out;
} protected <T> void writeOutputStream(DownloadDataLoader<T> loader, List<String> propertyNames,
Writer writer) throws Exception { int pageNum = 0;
int maxLenth = 102400;
while (maxLenth-- > 0) {
// 分页获取数据
List<T> objList = null;
try {
objList = loader.getDownloadData(pageNum++);
} catch (Exception e) {
LOGGER.error("获得到处数据异常:{}",e.getMessage(), e);
}
if (CollectionUtils.isEmpty(objList)) {
break;
}
for (T bean : objList) {
if (bean == null) {
continue;
}
Collection<String> result = new ArrayList<String>();
// 遍历指定属性
for (String name : propertyNames) {
// 获得属性值
Object property = loader.getProperty(bean, name);
// 将属性值转换成字符串
String convertValue = loader.convertProperty(bean, name, property);
// 组装成row
result.add(convertValue);
}
if (CollectionUtils.isEmpty(result)) {
continue;
}
writer.write(result);
}
} }
}

BaseController代码

package com.wjs.common.util.excel;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanMap;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
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.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.util.CollectionUtils; /**
*
* @author liqiang05
*
*/
public class ExcelUtils { /**
* logger
*/
private static final Logger logger = Logger.getLogger(ExcelUtils.class); /**
* 设置列格式
*
* @param sheet
* @param columnWidthList
*/
public static boolean setSheetStyle(Sheet sheet, List<Integer> columnWidthList) {
if (sheet == null || columnWidthList == null) {
return false;
}
// 设置所有列的宽度
for (int indx = 0, iMax = columnWidthList.size(); indx < iMax; indx++) {
Integer columnWidth = columnWidthList.get(indx);
if (columnWidth == null) {
continue;
}
sheet.setColumnWidth(indx, columnWidth.intValue() * 256);
}
return true;
} /**
* 设置行信息
*
* @param row
* @param rowObj
* @return
*/
public static boolean setRowInfo(Row row, Collection<Object> rowObj) {
if (row == null || rowObj == null) {
if (logger.isInfoEnabled()) {
logger.info("Row:" + row + ",rowObj" + rowObj);
}
return false;
}
// 填充每一列数据
int indxColumn = 0;
for (Object object : rowObj) {
Cell cell = row.createCell(indxColumn++);
if (object == null) {
if (logger.isDebugEnabled()) {
logger.debug("Row:" + row + ",Column:" + indxColumn + ",is empty");
}
continue;
}
String columnValue = object.toString();
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell.setCellValue(columnValue);
}
return true;
} /**
* 设置行信息
*
* @param row
* @param rowObj
* @param convert
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static boolean setRowInfo(Row row, Object rowObj, IExcelConvert convert) {
if (row == null || rowObj == null) {
if (logger.isInfoEnabled()) {
logger.info("Row:" + row + ",rowObj" + rowObj);
}
return false;
}
try {
Collection<Object> rowContent = null;
if (convert != null) {
rowContent = convert.convert(rowObj);
} else if (rowObj instanceof Map) {
rowContent = ((Map) rowObj).values();
} else if (rowObj instanceof Collection) {
rowContent = (Collection) rowObj;
} else {
rowContent = (new BeanMap(rowObj)).values();
}
if (rowContent == null || rowContent.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Row:" + row + ",is empty");
}
return false;
}
return setRowInfo(row, rowContent);
} catch (Throwable e) {
logger.info(rowObj + "convertFailed,row:" + row, e);
return false;
} } /**
* 将数据写入excel
*
* @param sheet
* @param columnWidth
* @param header
* @param content
* @return
*/
public static boolean setExcelInfo(Sheet sheet, List<Integer> columnWidth, List<String> header, List<?> rows) {
return setExcelInfo(sheet, columnWidth, header, rows, null);
} /**
* 将数据写入excel
*
* @param sheet
* @param columnWidth
* @param header
* @param content
* @param converter
* @return
*/
public static boolean setExcelInfo(Sheet sheet, List<Integer> columnWidth, List<String> header, List<?> content, IExcelConvert converter) {
if (sheet == null) {
logger.info("sheet is null");
return false;
}
// 设置sheet格式
setSheetStyle(sheet, columnWidth); // 设置头信息
int indxRow = 0;
Row row = sheet.createRow(indxRow++);
setRowInfo(row, header, null); // 如果内容为空 则退出
if (content == null || content.isEmpty()) {
logger.info("content is null,cannot write excel");
return true;
}
for (Object rowContent : content) {
row = sheet.createRow(indxRow++);
setRowInfo(row, rowContent, converter);
}
return true;
} /**
* 導出到excel
*
* @param title
* sheet Title
* @param columnWidthList
* 所有列的寬度,可以不指定
* @param content
* 內容, 每一項為一行,每一行內是List代表所有列
* @return
*/
public static Workbook setupXls(String title, List<Integer> columnWidthList, List<List<String>> content) { Workbook wb = new HSSFWorkbook();
Sheet sheet = wb.createSheet(title);
if (columnWidthList != null) {
// 设置所有列的宽度
for (int indx = 0, iMax = columnWidthList.size(); indx < iMax; indx++) {
Integer columnWidth = columnWidthList.get(indx);
if (columnWidth == null) {
continue;
}
sheet.setColumnWidth(indx, columnWidth.intValue() * 256);
}
} if (content == null || content.isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info("content is null,cannot write excel,title:" + title);
}
return wb;
} // 遍歷一行
for (int indxRow = 0, iMaxRow = content.size(); indxRow < iMaxRow; indxRow++) {
Row row = sheet.createRow(indxRow);
List<String> rowContent = content.get(indxRow);
if (rowContent == null || rowContent.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Row:" + indxRow + ",is empty,title:" + title);
}
continue;
}
// 填充每一列数据
for (int indxColumn = 0, iMaxColumn = rowContent.size(); indxColumn < iMaxColumn; indxColumn++) {
Cell cell = row.createCell(indxColumn);
String columnValue = rowContent.get(indxColumn);
if (columnValue == null || columnValue.length() == 0) {
if (logger.isDebugEnabled()) {
logger.debug("Row:" + indxRow + ",Column:" + indxColumn + ",is empty,title:" + title);
}
continue;
}
cell.setCellValue(columnValue);
}
}
return wb;
} /**
* 加載Excel 默認實現方式
*
* @param wb
* @return
*/
public static List<List<String>> loadXls(Workbook wb) {
// 默認 只讀第一個sheet, 且從第二行開始遍歷,默认读取到最大列
return loadXls(wb, 0, 1, 0);
} /**
* 加载excel
*
* @param wb
* @param sheetIndx
* 要加载excel的sheet页的index
* @param startRowIndx
* 要加载Row的index
* @param iMaxColumn
* 最大读到Cloumn的index
* @return List<List<>>
*/
public static List<List<String>> loadXls(Workbook wb, int sheetIndx, int startRowIndx, int iMaxColumn) {
List<List<String>> resList = new ArrayList<List<String>>();
if (wb == null || sheetIndx < 0 || startRowIndx < 0 || iMaxColumn < 0) {
logger.error("param error,return empty list,Workbook:" + wb + ",sheetIndex:" + sheetIndx + ",startRowNo:" + startRowIndx + ",iMaxColumn:" + iMaxColumn);
return resList;
}
Sheet sheet = wb.getSheetAt(sheetIndx);
if (sheet == null) {
logger.error("sheet is null,return empty list,Workbook:" + wb + ",sheetIndex:" + sheetIndx + ",startRowNo:" + startRowIndx);
return resList;
} // 從指定行開始遍歷
for (int indxRow = startRowIndx, iMaxRow = sheet.getLastRowNum(); indxRow <= iMaxRow; indxRow++) {
Row row = sheet.getRow(indxRow);
if (row == null) {
if (logger.isDebugEnabled()) {
logger.debug("Row is null,sheetIndex:" + sheetIndx + ",RowNo:" + indxRow);
}
continue;
}
List<String> rowContent = new ArrayList<String>();
// 當最大列為0時 讀取最大CellNum
if (iMaxColumn == 0) {
iMaxColumn = row.getLastCellNum();
}
boolean hasContent = false;
for (int indxColumn = 0; indxColumn < iMaxColumn; indxColumn++) {
String cellValue = null;
Cell cell = row.getCell(indxColumn);
if (cell == null) {
if (logger.isDebugEnabled()) {
logger.debug("Cell is null,sheetIndex:" + sheetIndx + ",RowNo:" + indxRow + ",CellNo:" + indxColumn);
}
} else {
cellValue = getCellStrValue(cell);
}
// 如果 读到的内容不是空 代表这行有数据
if (cellValue != null && cellValue.length() > 0) {
hasContent = true;
}
// 不论当前格是否有数据都加入.
rowContent.add(cellValue);
}
// 这一行有内容 则加入
if (hasContent) {
resList.add(rowContent);
}
}
return resList;
} public static String getCellStrValue(Cell cell) {
String res = "";
try {
res = cell.getStringCellValue();
} catch (Exception e) {
DecimalFormat df = new DecimalFormat("#");
res = df.format(cell.getNumericCellValue()) + "";
}
return res;
} /**
*
* @Description: 将集合转换成字符串输出
* @param coll
* @return 设定文件
* @throws 异常说明
* @author albert.su suzy@malam.com
* @date 2014年5月7日 下午12:35:55
*/
public static String collectionToCsvString(Collection<?> coll) {
if (CollectionUtils.isEmpty(coll)) {
return "";
}
StringBuilder sb = new StringBuilder();
Iterator<?> it = coll.iterator();
while (it.hasNext()) {
Object object = it.next();
if (String.valueOf(object).matches("[0-9,\\.]+") || String.valueOf(object).contains(",")) {
sb.append("\"\t");
sb.append(object);
sb.append("\"");
} else {
sb.append("\t");
sb.append(object);
}
if (it.hasNext()) {
sb.append(",");
}
}
return sb.toString();
} // 以下为糯米的代码, 建议少用 /**
* 从InputStream读取Excel workbook
*
* @param ins
* @return
* @throws IOException
* @throws FileNotFoundException
*/
public static HSSFWorkbook readWorkbook(InputStream ins) throws IOException, FileNotFoundException {
ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
BufferedInputStream bis = new BufferedInputStream(ins);
byte[] by = new byte[512];
int t = bis.read(by, 0, by.length);
while (t > 0) {
byteOS.write(by, 0, 512); // read 512
t = bis.read(by, 0, by.length);
}
byteOS.close();
InputStream byteIS = new ByteArrayInputStream(byteOS.toByteArray());
HSSFWorkbook wbDest = new HSSFWorkbook(byteIS);
return wbDest;
} public static void writeToResponse(HttpServletResponse response, HSSFWorkbook wb, String fileName) throws IOException {
response.setContentType("application/ms-download");
response.setCharacterEncoding("gb2312");
response.setHeader("Content-Disposition", "filename=" + fileName);
OutputStream out = response.getOutputStream();
wb.write(out);
out.flush();
out.close();
} /**
* 判断单元格的格式
*
* @param cell
* 单元格
* @return String 将excel各种单元格的类型转换为String类型
*/
public static String getCellStringValue(HSSFCell cell) {
// 转换后单元格的值
String value = "";
if (cell != null) {
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_STRING:
value = cell.getRichStringCellValue().getString();
break;
case HSSFCell.CELL_TYPE_NUMERIC:
if (HSSFDateUtil.isCellDateFormatted(cell)) {
Date date = HSSFDateUtil.getJavaDate(cell.getNumericCellValue());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
value = sdf.format(date);
} else {
DecimalFormat formatter = new DecimalFormat("########");
value = formatter.format(cell.getNumericCellValue());
}
break; case HSSFCell.CELL_TYPE_FORMULA:
cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
value = String.valueOf(cell.getNumericCellValue());
break; case HSSFCell.CELL_TYPE_BLANK:
break;
case HSSFCell.CELL_TYPE_BOOLEAN:
break;
case HSSFCell.CELL_TYPE_ERROR:
break;
default:
break;
}
}
return value;
} /**
* 到出excel的Helper类
*
* @author Administrator
*
*/
public static class ExcelRowBuilder { private HSSFRow row; private short index = 0; public ExcelRowBuilder(HSSFRow row) {
this.row = row;
} @SuppressWarnings("deprecation")
public ExcelRowBuilder addCell(String str) {
HSSFCell cell = row.createCell(index++);
cell.setCellValue(new HSSFRichTextString(str));
return this;
} @SuppressWarnings("deprecation")
public ExcelRowBuilder addCell(long value) {
HSSFCell cell = row.createCell(index++);
cell.setCellValue(value);
return this;
} @SuppressWarnings("deprecation")
public ExcelRowBuilder addCell(double value) {
HSSFCell cell = row.createCell(index++);
cell.setCellValue(value);
return this;
}
}
}

ExcelUtil代码

最新文章

  1. 第八章 交互技术,8.4 Weex 双11会场大规模应用的秒开实战和稳定性保障(作者:鬼道)
  2. 让动态的 iframe 内容高度自适应
  3. 北京易信软科信息技术有限公司 问卷调查管理系统V2.0
  4. ecshop 签名
  5. DJANGO基础学习之转义总结:escape,autoescape,safe,mark_safe
  6. netstat命令查看服务器运行情况
  7. This configuration file was broken by system-config-keyboard
  8. 用Delphi7开发Web Service程序 转
  9. poj2864
  10. android 4.2 root
  11. jQuery Mobile (整合版)
  12. canvas——路径搜索
  13. java线程同步小结
  14. Nuget私有服务搭建实战
  15. ansible学习(二)
  16. 学号 20175212 《Java程序设计》第九周学习总结
  17. Shiro+JWT+Spring Boot Restful简易教程
  18. JavaSE 软件工程师 认证考试试卷3
  19. Luogu4546 THUWC2017 在美妙的数学王国中畅游 LCT、泰勒展开
  20. python实现排序算法一:快速排序

热门文章

  1. HDU3991:Black and White
  2. c# namespace不能和class的name 相同
  3. Docker入门(二):安装/卸载
  4. python脚本修改hosts文件
  5. winform防止界面卡死的三种方法
  6. LeetCode: 389 Find the Difference(easy)
  7. Vue.js中,如何自己维护路由跳转记录?
  8. SQL中的limit
  9. 【转】mysql中set autocommit=0与start transaction的关系
  10. Codeforces Round #360 (Div. 1)A (二分图&dfs染色)