欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中使用EasyExcel并行導(dǎo)出多個(gè)excel文件并壓縮zip后下載的代碼詳解

 更新時(shí)間:2024年09月18日 09:08:18   作者:碼到三十五  
SpringBoot的同步導(dǎo)出方式中,服務(wù)器會(huì)阻塞直到Excel文件生成完畢,在處理大量數(shù)據(jù)的導(dǎo)出功能,本文給大家介紹了SpringBoot中使用EasyExcel并行導(dǎo)出多個(gè)excel文件并壓縮zip后下載,需要的朋友可以參考下

背景

SpringBoot的同步導(dǎo)出方式中,服務(wù)器會(huì)阻塞直到Excel文件生成完畢,在處理大量數(shù)據(jù)的導(dǎo)出功能,利用CompletableFuture,我們可以將導(dǎo)出任務(wù)異步化,最后 這些文件進(jìn)一步壓縮成ZIP格式以方便下載:

DEMO代碼:

@RestController
@RequestMapping("/export")
public class ExportController {

    @Autowired
    private ExcelExportService excelExportService;

    @GetMapping("/zip")
    public ResponseEntity<byte[]> exportToZip() throws Exception {
        List<List<Data>> dataSets = multipleDataSets();
        List<CompletableFuture<String>> futures = new ArrayList<>();
        // 異步導(dǎo)出所有Excel文件
         String outputDir = "path/to/output/dir/";
        for (List<Data> dataSet : dataSets) {
            futures.add(excelExportService.exportDataToExcel(dataSet, outputDir));
        }

        // 等待所有導(dǎo)出任務(wù)完成       
        CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).get(10, TimeUnit.MINUTES);;

        // 收集Excel文件路徑
        List<String> excelFilePaths = futures.stream()
                .map(CompletableFuture::join) // 獲取文件路徑
                .collect(Collectors.toList());

        // 壓縮文件
        File zipFile = new File("path/to/output.zip");
        try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) {
            for (String filePath : excelFilePaths) {
                zipFile(new File(filePath), zipOut, new File(filePath).getName());
            }
        }

        // 返回ZIP文件
        byte[] data = Files.readAllBytes(zipFile.toPath());
        return ResponseEntity.ok()
                .header("Content-Disposition", "attachment; filename=\"" + zipFile.getName() + "\"")
                .contentType(MediaType.parseMediaType("application/zip"))
                .body(data);
    }

    // 將文件添加到ZIP輸出流中  
    private void zipFile(File file, ZipOutputStream zipOut, String entryName) throws IOException {  
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {  
            ZipEntry zipEntry = new ZipEntry(entryName);  
            zipOut.putNextEntry(zipEntry);  
            byte[] bytesIn = new byte[4096];  
            int read;  
            while ((read = bis.read(bytesIn)) != -1) {  
                zipOut.write(bytesIn, 0, read);  
            }  
            zipOut.closeEntry();  
        }  
    } 

    // 獲取數(shù)據(jù)
    private List<List<Data>> multipleDataSets() {
    }
}

SpringBoot異步并行生成excel文件,利用EasyExcel庫(kù)來(lái)簡(jiǎn)化Excel的生成過(guò)程:

@Service
public class ExcelExportService {

    private static final String TEMPLATE_PATH = "path/to/template.xlsx";

    @Autowired
    private TaskExecutor taskExecutor; 

    public CompletableFuture<Void> exportDataToExcel(List<Data> dataList, String outputDir) {
        Path temproaryFilePath = Files.createTempFile(outputDir, "excelFilePre",".xlsx");
        return CompletableFuture.runAsync(() -> {
            try (OutputStream outputStream = new FileOutputStream(temproaryFilePath )) {
                EasyExcel.write(outputStream, Data.class)
                        .withTemplate(TEMPLATE_PATH)
                        .sheet()
                        .doFill(dataList)
                        .finish();
               return temproaryFilePath.toString();
            } catch (IOException e) {
                throw new RuntimeException("Failed to export Excel file", e);
            }
        }, taskExecutor);
    }
}

拓展:

一、簡(jiǎn)介

easyexcel 是阿里開(kāi)源的一款 Excel導(dǎo)入導(dǎo)出工具,具有處理速度快、占用內(nèi)存小、使用方便的特點(diǎn),底層邏輯也是基于 apache poi 進(jìn)行二次開(kāi)發(fā)的,目前的應(yīng)用也是非常廣!

相比 EasyPoi,EasyExcel 的處理數(shù)據(jù)性能非常高,讀取 75M (46W行25列) 的Excel,僅需使用 64M 內(nèi)存,耗時(shí) 20s,極速模式還可以更快!

廢話也不多說(shuō)了,下面直奔主題!

二、實(shí)踐

在 SpringBoot 項(xiàng)目中集成 EasyExcel 其實(shí)非常簡(jiǎn)單,僅需一個(gè)依賴即可。

<!--EasyExcel相關(guān)依賴-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.0.5</version>
</dependency>

EasyExcel 的導(dǎo)出導(dǎo)入支持兩種方式進(jìn)行處理

  • 第一種是通過(guò)實(shí)體類注解方式來(lái)生成文件和反解析文件數(shù)據(jù)映射成對(duì)象
  • 第二種是通過(guò)動(dòng)態(tài)參數(shù)化生成文件和反解析文件數(shù)據(jù)

下面我們以用戶信息的導(dǎo)出導(dǎo)入為例,分別介紹兩種處理方式。

簡(jiǎn)單導(dǎo)出

首先,我們只需要?jiǎng)?chuàng)建一個(gè)UserEntity用戶實(shí)體類,然后添加對(duì)應(yīng)的注解字段即可,示例代碼如下:

public class UserWriteEntity {

    @ExcelProperty(value = "姓名")
    private String name;
    
    @ExcelProperty(value = "年齡")
    private int age;
    
    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ExcelProperty(value = "操作時(shí)間")
    private Date time;
    
    //set、get...
}

然后,使用 EasyExcel 提供的EasyExcel工具類,即可實(shí)現(xiàn)文件的導(dǎo)出。

public static void main(String[] args) throws FileNotFoundException {
    List<UserWriteEntity> dataList = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        UserWriteEntity userEntity = new UserWriteEntity();
        userEntity.setName("張三" + i);
        userEntity.setAge(20 + i);
        userEntity.setTime(new Date(System.currentTimeMillis() + i));
        dataList.add(userEntity);
    }
    //定義文件輸出位置
    FileOutputStream outputStream = new FileOutputStream(new File("/Users/panzhi/Documents/easyexcel-export-user1.xlsx"));
    EasyExcel.write(outputStream, UserWriteEntity.class).sheet("用戶信息").doWrite(dataList);
}

運(yùn)行程序,打開(kāi)文件內(nèi)容結(jié)果!

簡(jiǎn)單導(dǎo)入

這種簡(jiǎn)單固定表頭的 Excel 文件,如果想要讀取文件數(shù)據(jù),操作也很簡(jiǎn)單。

以上面的導(dǎo)出文件為例,使用 EasyExcel 提供的EasyExcel工具類,即可來(lái)實(shí)現(xiàn)文件內(nèi)容數(shù)據(jù)的快速讀取,示例代碼如下:

首先創(chuàng)建讀取實(shí)體類

/**
 * 讀取實(shí)體類
 */
public class UserReadEntity {

    @ExcelProperty(value = "姓名")
    private String name;
    /**
     * 強(qiáng)制讀取第三個(gè) 這里不建議 index 和 name 同時(shí)用,要么一個(gè)對(duì)象只用index,要么一個(gè)對(duì)象只用name去匹配
     */
    @ExcelProperty(index = 1)
    private int age;
    
    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ExcelProperty(value = "操作時(shí)間")
    private Date time;
    
    //set、get...
}

然后讀取文件數(shù)據(jù),并封裝到對(duì)象里面

public static void main(String[] args) throws FileNotFoundException {
    //同步讀取文件內(nèi)容
    FileInputStream inputStream = new FileInputStream(new File("/Users/panzhi/Documents/easyexcel-user1.xls"));
    List<UserReadEntity> list = EasyExcel.read(inputStream).head(UserReadEntity.class).sheet().doReadSync();
    System.out.println(JSONArray.toJSONString(list));
}

運(yùn)行程序,輸出結(jié)果如下:

[{"age":20,"name":"張三0","time":1616920360000},{"age":21,"name":"張三1","time":1616920360000},{"age":22,"name":"張三2","time":1616920360000},{"age":23,"name":"張三3","time":1616920360000},{"age":24,"name":"張三4","time":1616920360000},{"age":25,"name":"張三5","time":1616920360000},{"age":26,"name":"張三6","time":1616920360000},{"age":27,"name":"張三7","time":1616920360000},{"age":28,"name":"張三8","time":1616920360000},{"age":29,"name":"張三9","time":1616920360000}]

動(dòng)態(tài)自由導(dǎo)出導(dǎo)入

在實(shí)際使用開(kāi)發(fā)中,我們不可能每來(lái)一個(gè) excel 導(dǎo)入導(dǎo)出需求,就編寫(xiě)一個(gè)實(shí)體類,很多業(yè)務(wù)需求需要根據(jù)不同的字段來(lái)動(dòng)態(tài)導(dǎo)入導(dǎo)出,沒(méi)辦法基于實(shí)體類注解的方式來(lái)讀取文件或者寫(xiě)入文件。

因此,基于EasyExcel提供的動(dòng)態(tài)參數(shù)化生成文件和動(dòng)態(tài)監(jiān)聽(tīng)器讀取文件方法,我們可以單獨(dú)封裝一套動(dòng)態(tài)導(dǎo)出導(dǎo)出工具類,省的我們每次都需要重新編寫(xiě)大量重復(fù)工作,以下就是小編我在實(shí)際使用過(guò)程,封裝出來(lái)的工具類,在此分享給大家!

首先,我們可以編寫(xiě)一個(gè)動(dòng)態(tài)導(dǎo)出工具類

public class DynamicEasyExcelExportUtils {

    private static final Logger log = LoggerFactory.getLogger(DynamicEasyExcelExportUtils.class);

    private static final String DEFAULT_SHEET_NAME = "sheet1";

    /**
     * 動(dòng)態(tài)生成導(dǎo)出模版(單表頭)
     * @param headColumns 列名稱
     * @return            excel文件流
     */
    public static byte[] exportTemplateExcelFile(List<String> headColumns){
        List<List<String>> excelHead = Lists.newArrayList();
        headColumns.forEach(columnName -> { excelHead.add(Lists.newArrayList(columnName)); });
        byte[] stream = createExcelFile(excelHead, new ArrayList<>());
        return stream;
    }

    /**
     * 動(dòng)態(tài)生成模版(復(fù)雜表頭)
     * @param excelHead   列名稱
     * @return
     */
    public static byte[] exportTemplateExcelFileCustomHead(List<List<String>> excelHead){
        byte[] stream = createExcelFile(excelHead, new ArrayList<>());
        return stream;
    }

    /**
     * 動(dòng)態(tài)導(dǎo)出文件(通過(guò)map方式計(jì)算)
     * @param headColumnMap  有序列頭部
     * @param dataList       數(shù)據(jù)體
     * @return
     */
    public static byte[] exportExcelFile(LinkedHashMap<String, String> headColumnMap, List<Map<String, Object>> dataList){
        //獲取列名稱
        List<List<String>> excelHead = new ArrayList<>();
        if(MapUtils.isNotEmpty(headColumnMap)){
            //key為匹配符,value為列名,如果多級(jí)列名用逗號(hào)隔開(kāi)
            headColumnMap.entrySet().forEach(entry -> {
                excelHead.add(Lists.newArrayList(entry.getValue().split(",")));
            });
        }
        List<List<Object>> excelRows = new ArrayList<>();
        if(MapUtils.isNotEmpty(headColumnMap) && CollectionUtils.isNotEmpty(dataList)){
            for (Map<String, Object> dataMap : dataList) {
                List<Object> rows = new ArrayList<>();
                headColumnMap.entrySet().forEach(headColumnEntry -> {
                    if(dataMap.containsKey(headColumnEntry.getKey())){
                        Object data = dataMap.get(headColumnEntry.getKey());
                        rows.add(data);
                    }
                });
                excelRows.add(rows);
            }
        }
        byte[] stream = createExcelFile(excelHead, excelRows);
        return stream;
    }


    /**
     * 生成文件(自定義頭部排列)
     * @param rowHeads
     * @param excelRows
     * @return
     */
    public static byte[] customerExportExcelFile(List<List<String>> rowHeads, List<List<Object>> excelRows){
        //將行頭部轉(zhuǎn)成easyexcel能識(shí)別的部分
        List<List<String>> excelHead = transferHead(rowHeads);
        return createExcelFile(excelHead, excelRows);
    }

    /**
     * 生成文件
     * @param excelHead
     * @param excelRows
     * @return
     */
    private static byte[] createExcelFile(List<List<String>> excelHead, List<List<Object>> excelRows){
        try {
            if(CollectionUtils.isNotEmpty(excelHead)){
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                EasyExcel.write(outputStream).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        .head(excelHead)
                        .sheet(DEFAULT_SHEET_NAME)
                        .doWrite(excelRows);
                return outputStream.toByteArray();
            }
        } catch (Exception e) {
            log.error("動(dòng)態(tài)生成excel文件失敗,headColumns:" + JSONArray.toJSONString(excelHead) + ",excelRows:" + JSONArray.toJSONString(excelRows), e);
        }
        return null;
    }

    /**
     * 將行頭部轉(zhuǎn)成easyexcel能識(shí)別的部分
     * @param rowHeads
     * @return
     */
    public static List<List<String>> transferHead(List<List<String>> rowHeads){
        //將頭部列進(jìn)行反轉(zhuǎn)
        List<List<String>> realHead = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(rowHeads)){
            Map<Integer, List<String>> cellMap = new LinkedHashMap<>();
            //遍歷行
            for (List<String> cells : rowHeads) {
                //遍歷列
                for (int i = 0; i < cells.size(); i++) {
                    if(cellMap.containsKey(i)){
                        cellMap.get(i).add(cells.get(i));
                    } else {
                        cellMap.put(i, Lists.newArrayList(cells.get(i)));
                    }
                }
            }
            //將列一行一行加入realHead
            cellMap.entrySet().forEach(item -> realHead.add(item.getValue()));
        }
        return realHead;
    }

    /**
     * 導(dǎo)出文件測(cè)試
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        //導(dǎo)出包含數(shù)據(jù)內(nèi)容的文件(方式一)
        LinkedHashMap<String, String> headColumnMap = Maps.newLinkedHashMap();
        headColumnMap.put("className","班級(jí)");
        headColumnMap.put("name","學(xué)生信息,姓名");
        headColumnMap.put("sex","學(xué)生信息,性別");
        List<Map<String, Object>> dataList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Map<String, Object> dataMap = Maps.newHashMap();
            dataMap.put("className", "一年級(jí)");
            dataMap.put("name", "張三" + i);
            dataMap.put("sex", "男");
            dataList.add(dataMap);
        }
        byte[] stream1 = exportExcelFile(headColumnMap, dataList);
        FileOutputStream outputStream1 = new FileOutputStream(new File("/Users/panzhi/Documents/easyexcel-export-user5.xlsx"));
        outputStream1.write(stream1);
        outputStream1.close();


        //導(dǎo)出包含數(shù)據(jù)內(nèi)容的文件(方式二)
        //頭部,第一層
        List<String> head1 = new ArrayList<>();
        head1.add("第一行頭部列1");
        head1.add("第一行頭部列1");
        head1.add("第一行頭部列1");
        head1.add("第一行頭部列1");
        //頭部,第二層
        List<String> head2 = new ArrayList<>();
        head2.add("第二行頭部列1");
        head2.add("第二行頭部列1");
        head2.add("第二行頭部列2");
        head2.add("第二行頭部列2");
        //頭部,第三層
        List<String> head3 = new ArrayList<>();
        head3.add("第三行頭部列1");
        head3.add("第三行頭部列2");
        head3.add("第三行頭部列3");
        head3.add("第三行頭部列4");

        //封裝頭部
        List<List<String>> allHead = new ArrayList<>();
        allHead.add(head1);
        allHead.add(head2);
        allHead.add(head3);

        //封裝數(shù)據(jù)體
        //第一行數(shù)據(jù)
        List<Object> data1 = Lists.newArrayList(1,1,1,1);
        //第二行數(shù)據(jù)
        List<Object> data2 = Lists.newArrayList(2,2,2,2);
        List<List<Object>> allData = Lists.newArrayList(data1, data2);

        byte[] stream2 = customerExportExcelFile(allHead, allData);
        FileOutputStream outputStream2 = new FileOutputStream(new File("/Users/panzhi/Documents/easyexcel-export-user6.xlsx"));
        outputStream2.write(stream2);
        outputStream2.close();


    }
}

然后,編寫(xiě)一個(gè)動(dòng)態(tài)導(dǎo)入工具類

/**
 * 創(chuàng)建一個(gè)文件讀取監(jiān)聽(tīng)器
 */
public class DynamicEasyExcelListener extends AnalysisEventListener<Map<Integer, String>> {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserDataListener.class);
    /**
     * 表頭數(shù)據(jù)(存儲(chǔ)所有的表頭數(shù)據(jù))
     */
    private List<Map<Integer, String>> headList = new ArrayList<>();
    /**
     * 數(shù)據(jù)體
     */
    private List<Map<Integer, String>> dataList = new ArrayList<>();
    /**
     * 這里會(huì)一行行的返回頭
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        LOGGER.info("解析到一條頭數(shù)據(jù):{}", JSON.toJSONString(headMap));
        //存儲(chǔ)全部表頭數(shù)據(jù)
        headList.add(headMap);
    }
    /**
     * 這個(gè)每一條數(shù)據(jù)解析都會(huì)來(lái)調(diào)用
     *
     * @param data
     *            one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        LOGGER.info("解析到一條數(shù)據(jù):{}", JSON.toJSONString(data));
        dataList.add(data);
    }
    /**
     * 所有數(shù)據(jù)解析完成了 都會(huì)來(lái)調(diào)用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 這里也要保存數(shù)據(jù),確保最后遺留的數(shù)據(jù)也存儲(chǔ)到數(shù)據(jù)庫(kù)
        LOGGER.info("所有數(shù)據(jù)解析完成!");
    }
    public List<Map<Integer, String>> getHeadList() {
        return headList;
    }
    public List<Map<Integer, String>> getDataList() {
        return dataList;
    }
}

動(dòng)態(tài)導(dǎo)入工具類

/**
 * 編寫(xiě)導(dǎo)入工具類
 */
public class DynamicEasyExcelImportUtils {
    /**
     * 動(dòng)態(tài)獲取全部列和數(shù)據(jù)體,默認(rèn)從第一行開(kāi)始解析數(shù)據(jù)
     * @param stream
     * @return
     */
    public static List<Map<String,String>> parseExcelToView(byte[] stream) {
        return parseExcelToView(stream, 1);
    }
    /**
     * 動(dòng)態(tài)獲取全部列和數(shù)據(jù)體
     * @param stream           excel文件流
     * @param parseRowNumber   指定讀取行
     * @return
     */
    public static List<Map<String,String>> parseExcelToView(byte[] stream, Integer parseRowNumber) {
        DynamicEasyExcelListener readListener = new DynamicEasyExcelListener();
        EasyExcelFactory.read(new ByteArrayInputStream(stream)).registerReadListener(readListener).headRowNumber(parseRowNumber).sheet(0).doRead();
        List<Map<Integer, String>> headList = readListener.getHeadList();
        if(CollectionUtils.isEmpty(headList)){
            throw new RuntimeException("Excel未包含表頭");
        }
        List<Map<Integer, String>> dataList = readListener.getDataList();
        if(CollectionUtils.isEmpty(dataList)){
            throw new RuntimeException("Excel未包含數(shù)據(jù)");
        }
        //獲取頭部,取最后一次解析的列頭數(shù)據(jù)
        Map<Integer, String> excelHeadIdxNameMap = headList.get(headList.size() -1);
        //封裝數(shù)據(jù)體
        List<Map<String,String>> excelDataList = Lists.newArrayList();
        for (Map<Integer, String> dataRow : dataList) {
            Map<String,String> rowData = new LinkedHashMap<>();
            excelHeadIdxNameMap.entrySet().forEach(columnHead -> {
                rowData.put(columnHead.getValue(), dataRow.get(columnHead.getKey()));
            });
            excelDataList.add(rowData);
        }
        return excelDataList;
    }
    /**
     * 文件導(dǎo)入測(cè)試
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        FileInputStream inputStream = new FileInputStream(new File("/Users/panzhi/Documents/easyexcel-export-user5.xlsx"));
        byte[] stream = IoUtils.toByteArray(inputStream);
        List<Map<String,String>> dataList = parseExcelToView(stream, 2);
        System.out.println(JSONArray.toJSONString(dataList));
        inputStream.close();
    }
}

為了方便后續(xù)的操作流程,在解析數(shù)據(jù)的時(shí)候,會(huì)將列名作為key!

以上就是SpringBoot中使用EasyExcel并行導(dǎo)出多個(gè)excel文件并壓縮zip后下載的代碼詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot EasyExcel導(dǎo)出excel并下載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot項(xiàng)目中如何解決跨域問(wèn)題的最新方案?

    SpringBoot項(xiàng)目中如何解決跨域問(wèn)題的最新方案?

    跨域問(wèn)題是瀏覽器為了保護(hù)用戶的信息安全,實(shí)施了同源策略(Same-Origin Policy),即只允許頁(yè)面請(qǐng)求同源(相同協(xié)議、域名和端口)的資源,當(dāng) JavaScript 發(fā)起的請(qǐng)求跨越了同源策略,即請(qǐng)求的目標(biāo)與當(dāng)前頁(yè)面的域名、端口、協(xié)議不一致時(shí),瀏覽器會(huì)阻止請(qǐng)求的發(fā)送或接收
    2025-03-03
  • 全面了解Java中的內(nèi)部類和匿名類

    全面了解Java中的內(nèi)部類和匿名類

    下面小編就為大家?guī)?lái)一篇全面了解Java中的內(nèi)部類和匿名類。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07
  • 學(xué)習(xí)Java多線程之同步

    學(xué)習(xí)Java多線程之同步

    這篇文章主要為大家詳細(xì)介紹了Java多線程之同步,感興趣的小伙伴們可以參考一下
    2016-02-02
  • java過(guò)濾器中Filter的ChainFilter過(guò)濾鏈

    java過(guò)濾器中Filter的ChainFilter過(guò)濾鏈

    這篇文章主要介紹了java過(guò)濾器中Filter的ChainFilter過(guò)濾鏈,發(fā)送請(qǐng)求時(shí),如果有不符合的信息將會(huì)被filter進(jìn)行攔截,如果符合則會(huì)進(jìn)行放行。如果感興趣可以來(lái)學(xué)習(xí)一下
    2020-07-07
  • 如何利用Ganymed SSH-2模擬SSH操作

    如何利用Ganymed SSH-2模擬SSH操作

    這幾天看SFTP資料時(shí),無(wú)意中看到了Ganymed SSH-2,寫(xiě)了個(gè)簡(jiǎn)單demo,通過(guò),感覺(jué)挺好用的,下面就和大家分享下。需要的朋友可以過(guò)來(lái)參考參考
    2013-08-08
  • MyBatis?多表聯(lián)合查詢及優(yōu)化方法

    MyBatis?多表聯(lián)合查詢及優(yōu)化方法

    大家都知道Hibernate 是全自動(dòng)的數(shù)據(jù)庫(kù)持久層框架,它可以通過(guò)實(shí)體來(lái)映射數(shù)據(jù)庫(kù),通過(guò)設(shè)置一對(duì)多、多對(duì)一、一對(duì)一、多對(duì)多的關(guān)聯(lián)來(lái)實(shí)現(xiàn)聯(lián)合查詢,接下來(lái)通過(guò)本文給大家介紹MyBatis?多表聯(lián)合查詢及優(yōu)化,需要的朋友可以參考下
    2022-08-08
  • 淺談SpringMVC中Interceptor和Filter區(qū)別

    淺談SpringMVC中Interceptor和Filter區(qū)別

    這篇文章主要介紹了淺談SpringMVC中Interceptor和Filter區(qū)別,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-04-04
  • springboot~nexus項(xiàng)目打包要注意的地方示例代碼詳解

    springboot~nexus項(xiàng)目打包要注意的地方示例代碼詳解

    這篇文章主要介紹了springboot~nexus項(xiàng)目打包要注意的地方,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java DFA算法案例詳解

    Java DFA算法案例詳解

    這篇文章主要介紹了Java DFA算法案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java中List for循環(huán)的6種寫(xiě)法總結(jié)(推薦)

    Java中List for循環(huán)的6種寫(xiě)法總結(jié)(推薦)

    下面小編就為大家?guī)?lái)一篇Java中List for循環(huán)的6種寫(xiě)法總結(jié)(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06

最新評(píng)論