前言:前段时间在写表格导出的时候,需要导出的数据集合需要循环处理,但是速度太慢,所以看了一下如何使用多线程加快导出速度,如有不足之处,请多批评指正。
注意:对象类实现Cloneable接口,不然导出会发现数据混乱。
@Data
public class EmployeeException extends BaseObject implements Cloneable {
private String employeeId;
private Date exceptionDate;
private Integer exceptionType;
private String name;
private String startTime;
private String endTime;
private String departmentId;
private String projectId;
private String signInTime;
private String signLocation;
private String signOutTime;
private String signOutLocation;
private String projectName;
private String startTimeForCut;
private String endTimeForCut;
private Integer status;
@Override
public EmployeeException clone ( ) throws CloneNotSupportedException {
return ( EmployeeException) super . clone ( ) ;
}
}
1、Controller层方法
public void exportEmployeeException( employeeException) {
ByteArrayOutputStream os = new ByteArrayOutputStream( ) ;
InputStream inStream = null ;
OutputStream outputStream = null ;
String isExport = "succ" ;
HttpSession session = this. getServletRequest( ) . getSession( ) ;
try {
employeeExceptionService. exportEmployeeException2( employeeException, os) ;
String fileName = URLEncoder. encode( dateFormat. format ( new Date ( ) ) + "列表" ) ;
os. flush( ) ;
byte[ ] buf = os. toByteArray( ) ;
log. info( "生成excel长度:" + buf. length + "字节" ) ;
inStream = new ByteArrayInputStream( buf) ;
this. getServletResponse( ) . reset( ) ;
this. getServletResponse( ) . setContentType( "application/vnd.ms-excel" ) ;
this. getServletResponse( ) . setCharacterEncoding( "UTF-8" ) ;
this. getServletResponse( ) . addHeader( "Content-Disposition" ,
"attachment; filename=\"" + fileName + ".xlsx\"" ) ;
byte[ ] b = new byte[ 1024 ] ;
int len;
outputStream = this. getServletResponse( ) . getOutputStream( ) ;
while ( ( len = inStream. read ( b) ) > 0 ) {
outputStream. write ( b, 0 , len) ;
}
} catch ( Exception e) {
log. error( "{}" , e) ;
isExport = "fail" ;
} finally {
try {
if ( os != null ) {
os. close ( ) ;
}
if ( inStream != null ) {
inStream. close ( ) ;
}
if ( outputStream != null ) {
outputStream. close ( ) ;
}
} catch ( Exception e) {
logger. error( "os close exception!!" , e) ;
}
session . setAttribute( "isExport" , isExport) ;
}
}
2、service层方法
注:handleList(employeeException, employeeExceptionList, 5)方法用到了多线程的知识。
public void exportEmployeeException2( EmployeeException employeeException, ByteArrayOutputStream os) throws InterruptedException {
List< EmployeeException> employeeExceptionList = employeeExceptionMapper. selectAllEmployeeExceptionList( employeeException) ;
handleList( employeeException, employeeExceptionList, 5 ) ;
ArrayList< Map< String, String>> data = new ArrayList<> ( ) ;
for ( EmployeeExceptionExport employeeExceptionExport : employeeExceptionExportList) {
Map< String, String> map1 = ObjectUtil. objectToMap( employeeExceptionExport, "" ) ;
data . add ( map1) ;
}
int [ ] headWidth = new int [ ] {15 , 15 , 15 };
LinkedHashMap< String, String> relation = new LinkedHashMap<> ( ) ;
relation. put( "员工姓名" , "employeeName" ) ;
relation. put( "员工性别" , "sex" ) ;
relation. put( "员工手机号" , "phone" ) ;
log. info( "导出报表完成" ) ;
BaseExcelExportUtils baseExcelExportUtils = new BaseExcelExportUtils( headWidth) {
@Override
public String setCellStyle( Cell cell, String attrStr) {
return null ;
}
};
baseExcelExportUtils. exportInwork( data , os, relation, "异常扣分导出表" ) ;
}
3、handleList(employeeException, employeeExceptionList, 5)方法,employeeExceptionList即为要处理的集合。
public synchronized void handleList( EmployeeException employeeException, List< EmployeeException> data , int threadNum) throws InterruptedException {
ExecutorService executorService = Executors. newFixedThreadPool( 5 ) ;
int length = data . size( ) ;
int tl = length % threadNum = = 0 ? length / threadNum : ( length
/ threadNum + 1 ) ;
long l = System. currentTimeMillis( ) ;
for ( int i = 0 ; i < threadNum; i+ + ) {
int end = ( i + 1 ) * tl;
EmployeeException clone = null ;
try {
clone = employeeException. clone( ) ;
} catch ( CloneNotSupportedException e) {
e. printStackTrace( ) ;
}
executorService. execute ( new HandleThread( "线程[" + ( i + 1 ) + "] " , data , i * tl, end > length ? length : end , clone) ) ;
}
executorService. shutdown ( ) ;
while ( true ) {
if ( executorService. isTerminated( ) ) {
System. out . println( "结束了!" ) ;
long l1 = System. currentTimeMillis( ) ;
long time = l1 - l;
System. out . println( time ) ;
break ;
}
Thread. sleep( 200 ) ;
}
}
class HandleThread extends Thread {
private String threadName;
private List< EmployeeException> data ;
private int start ;
private int end ;
private EmployeeException employeeException;
public HandleThread( String threadName, List< EmployeeException> data , int start , int end , EmployeeException employeeException) {
this. threadName = threadName;
this. data = data ;
this. start = start ;
this. end = end ;
this. employeeException = employeeException;
}
public void run( ) {
List< EmployeeException> employeeExceptionList = data . subList( start , end ) ;
for ( EmployeeException exception : employeeExceptionList) {
}
4、BaseExcelExportUtils导出表格工具类。
@Slf4j
@NoArgsConstructor
public abstract class BaseExcelExportUtils {
private int [ ] headWidth;
private Map< String, CellStyle> styles;
public BaseExcelExportUtils( int [ ] headWidth) {
this. headWidth = headWidth;
}
private static Map< String, CellStyle> createStyles( Workbook wb) {
Map< String, CellStyle> styles = new HashMap< String, CellStyle> ( ) ;
DataFormat df = wb. createDataFormat( ) ;
CellStyle style;
Font headerFont = wb. createFont( ) ;
headerFont. setBoldweight( Font. BOLDWEIGHT_BOLD) ;
style = createBorderedStyle( wb) ;
style. setAlignment( CellStyle. ALIGN_CENTER) ;
style. setFillForegroundColor( IndexedColors. LIGHT_CORNFLOWER_BLUE
. getIndex( ) ) ;
style. setFillPattern( CellStyle. SOLID_FOREGROUND) ;
style. setFont( headerFont) ;
style. setDataFormat( df. getFormat( "text" ) ) ;
styles. put( "header" , style) ;
style = createBorderedStyle( wb) ;
style. setAlignment( CellStyle. ALIGN_LEFT) ;
style. setWrapText( true ) ;
style. setDataFormat( df. getFormat( "text" ) ) ;
style. setLocked( true ) ;
styles. put( "cell_normal" , style) ;
style = createBorderedStyle( wb) ;
style. setAlignment( CellStyle. ALIGN_RIGHT) ;
style. setWrapText( true ) ;
style. setDataFormat( df. getFormat( "text" ) ) ;
style. setLocked( true ) ;
styles. put( "cell_decimal" , style) ;
style = createBorderedStyle( wb) ;
style. setAlignment( CellStyle. ALIGN_LEFT) ;
style. setWrapText( true ) ;
style. setDataFormat( df. getFormat( "text" ) ) ;
style. setLocked( false ) ;
styles. put( "cell_normal_writable" , style) ;
style = createBorderedStyle( wb) ;
style. setAlignment( CellStyle. ALIGN_RIGHT) ;
style. setWrapText( true ) ;
style. setDataFormat( df. getFormat( "text" ) ) ;
style. setLocked( false ) ;
styles. put( "cell_decimal_writable" , style) ;
style = createBorderedStyle( wb) ;
style. setAlignment( CellStyle. ALIGN_CENTER) ;
style. setFillForegroundColor( IndexedColors. RED
. getIndex( ) ) ;
style. setFillPattern( CellStyle. SOLID_FOREGROUND) ;
style. setDataFormat( df. getFormat( "text" ) ) ;
styles. put( "cell_red" , style) ;
style = createBorderedStyle( wb) ;
style. setAlignment( CellStyle. ALIGN_CENTER) ;
style. setFillForegroundColor( IndexedColors. YELLOW
. getIndex( ) ) ;
style. setFillPattern( CellStyle. SOLID_FOREGROUND) ;
style. setDataFormat( df. getFormat( "text" ) ) ;
styles. put( "cell_yellow" , style) ;
style = createBorderedStyle( wb) ;
style. setAlignment( CellStyle. ALIGN_CENTER) ;
style. setFillForegroundColor( IndexedColors. SKY_BLUE
. getIndex( ) ) ;
style. setFillPattern( CellStyle. SOLID_FOREGROUND) ;
style. setDataFormat( df. getFormat( "text" ) ) ;
styles. put( "cell_skyblue" , style) ;
return styles;
}
private static CellStyle createBorderedStyle( Workbook wb) {
CellStyle style = wb. createCellStyle( ) ;
style. setBorderRight( CellStyle. BORDER_THIN) ;
style. setRightBorderColor( IndexedColors. BLACK. getIndex( ) ) ;
style. setBorderBottom( CellStyle. BORDER_THIN) ;
style. setBottomBorderColor( IndexedColors. BLACK. getIndex( ) ) ;
style. setBorderLeft( CellStyle. BORDER_THIN) ;
style. setLeftBorderColor( IndexedColors. BLACK. getIndex( ) ) ;
style. setBorderTop( CellStyle. BORDER_THIN) ;
style. setTopBorderColor( IndexedColors. BLACK. getIndex( ) ) ;
return style;
}
public abstract String setCellStyle( Cell cell, String attrStr) ;
public void exportInwork( List< Map< String, String>> data , ByteArrayOutputStream os, ExcelHeaderRelationship excelHeaderRelationship, String title) {
try {
XSSFWorkbook wb = new XSSFWorkbook( ) ;
styles = createStyles( wb) ;
if ( data != null && data . size( ) > 0 ) {
Cell cell = null ;
Row row ;
XSSFSheet sheet = wb. createSheet( title) ;
initExcle( sheet) ;
TreeMap< String, String> relations = excelHeaderRelationship. getRelations( ) ;
List< String> relaList = initHeader( sheet, relations) ;
for ( int i = 1 ; i <= data . size( ) ; i+ + ) {
row = sheet. createRow( i) ;
Map< String, String> rowData = data . get( i - 1 ) ;
for ( int j = 0 ; j <= relaList. size( ) ; j+ + ) {
cell = row . createCell( j) ;
if ( j = = 0 ) {
cell. setCellValue( i) ;
cell. setCellStyle( styles. get( "cell_normal" ) ) ;
} else {
String attrStr = relations. get( relaList. get( j - 1 ) ) ;
String valStr = rowData. get( attrStr) ;
cell. setCellValue( valStr) ;
cell. setCellStyle( styles. get( setCellStyle( cell, attrStr) ) ) ;
}
}
}
wb. write ( os) ;
}
} catch ( Exception e) {
log. error( "{}" , e) ;
}
}
public void exportInwork( List< Map< String, String>> data , ByteArrayOutputStream os, Map< String, String> relation, String title) {
try {
log. info( "创建excel" ) ;
XSSFWorkbook wb = new XSSFWorkbook( ) ;
styles = createStyles( wb) ;
log. info( "init excle" ) ;
Cell cell = null ;
Row row ;
XSSFSheet sheet = wb. createSheet( title) ;
initExcle( sheet) ;
log. info( "init header" ) ;
List< String> relaList = initHeader( sheet, relation) ;
if ( data != null && data . size( ) > 0 ) {
log. info( "init body" ) ;
for ( int i = 1 ; i <= data . size( ) ; i+ + ) {
row = sheet. createRow( i) ;
Map< String, String> rowData = data . get( i - 1 ) ;
for ( int j = 0 ; j <= relaList. size( ) ; j+ + ) {
cell = row . createCell( j) ;
if ( j = = 0 ) {
cell. setCellValue( i) ;
cell. setCellStyle( styles. get( "cell_normal" ) ) ;
} else {
String attrStr = relation. get( relaList. get( j - 1 ) ) ;
String valStr = String. valueOf( rowData. get( attrStr) ) ;
cell. setCellValue( valStr) ;
cell. setCellStyle( styles. get( setCellStyle( cell, attrStr) ) ) ;
}
}
}
}
wb. write ( os) ;
log. info( "完成生成excel" ) ;
} catch ( Exception e) {
log. error( "{}" , e) ;
}
}
private void initExcle( XSSFSheet sheet) {
sheet. setDisplayGridlines( true ) ;
sheet. setPrintGridlines( true ) ;
sheet. setFitToPage( true ) ;
sheet. setHorizontallyCenter( true ) ;
PrintSetup printSetup = sheet. getPrintSetup( ) ;
printSetup. setLandscape( true ) ;
sheet. setAutobreaks( true ) ;
printSetup. setFitHeight( ( short) 1 ) ;
printSetup. setFitWidth( ( short) 1 ) ;
}
private List< String> initHeader( XSSFSheet sheet, Map< String, String> relations) {
Row dataRow = sheet. createRow( 0 ) ;
Set < String> keys = relations. keySet( ) ;
Set < Map. Entry< String, String>> entries = relations. entrySet( ) ;
Iterator< String> iterator = keys . iterator( ) ;
List< String> relaList = new ArrayList<> ( ) ;
int k = 0 ;
Cell noCell = dataRow. createCell( k) ;
noCell. setCellValue( "序号" ) ;
noCell. setCellStyle( styles. get( "header" ) ) ;
sheet. setColumnWidth( k, 256 * headWidth[ k] ) ;
k+ + ;
while ( iterator. hasNext( ) ) {
String key = iterator. next ( ) ;
relaList. add ( key ) ;
Cell cell = dataRow. createCell( k) ;
cell. setCellValue( key ) ;
cell. setCellStyle( styles. get( "header" ) ) ;
sheet. setColumnWidth( k, 256 * headWidth[ k] ) ;
k+ + ;
}
return relaList;
}
}