One-click export: using Java to implement a weekly report Excel file in a custom format

foreword

Let me introduce a powerful weekly report export tool written in Java, which can export weekly report data to Excel for easy management and reference. This tool uses Apache POIlibraries to process Excel files, ensuring that the resulting Excel files have high-quality formatting and styling.

background

In daily work, many companies need to fill in and submit weekly reports on a regular basis in order to better track project progress and the work of team members. There are some problems in the traditional manual filling of weekly reports, such as time-consuming and error-prone. In order to improve efficiency and accuracy, we use Java to write a weekly report export tool, which can extract data from the database according to the specified time range, and export the weekly report as an Excel file.

1. Tool function

Our weekly reporting tool has the following key features:

  1. Export weekly report data within a specified time range.
  2. Group the weekly report data according to the project leader and generate the corresponding Excel table.
  3. Summarize the working hours of each project leader from Monday to Sunday for the project.
  4. Provide certain format and style control on the exported data to make the content of the weekly report more beautiful.
  5. Automatically calculate total hours and project summary information.

2. Implementation details

1. Parameter verification

First, we verify the incoming date parameters to ensure the legitimacy of the date range.

2. Data acquisition and processing

We obtain all project information and member information through database query, and obtain the working hours details of each project according to the specified time range. Then, we group the data and group the data according to the project leader, so as to generate Excel tables later.

3. Excel table generation

Next, we use the Apache POI library to generate Excel tables. We set header rows, styles, merged cells, etc. to ensure table readability and aesthetics.

4. Data filling

We populate the Excel sheet with the data queried from the database. According to the number of projects each project leader is responsible for, cells are dynamically merged to facilitate the display of project information.

5. Calculation of total working hours

After adding the working hours data from Monday to Sunday in the table, we calculate and populate the total working hours from Monday to Sunday for all projects that each project leader is responsible for.

6. Summary summary

Finally, we aggregated the summary information of all the projects that each project leader is responsible for and added it to an Excel sheet.

7. File export

The final step is to provide the generated Excel file to the user for download through HTTP response.

3. Practical development

1. Maven

<!--POI解析excel-->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.17</version>
		</dependency>
		<!-- Excel Xlsx格式解析 -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.17</version>
		</dependency>

2. Core guide package import

import javafx.util.Pair;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

3. Business code

public void exportWeekReportToExcel(HttpServletResponse response, LocalDate startDatetime, LocalDate endDatetime) {
    
    
    {
    
    
        //校验参数
        validateDateRange(startDatetime,endDatetime);
        //分割时间一周
        List<Pair<LocalDate, LocalDate>> pairs = DayOfWeekUtil.splitTimeByWeek(startDatetime, endDatetime);
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("项目周报");
        //获取所有的项目信息和成员信息
        List<ProjectMembersEntry> projectMembersEntries = stWorkLogMapper.selectProjectMembers();
        int rowNumber = 0;
        for (Pair<LocalDate, LocalDate> pair : pairs) {
    
    
            LocalDate weekStartDate = pair.getKey();
            LocalDate weekEndDate = pair.getValue();
            //获取所有用户的的所有项目的工时明细
            List<WorkTimesEntry> workTimesEntries = stWorkLogMapper.selectWorkTimes(weekStartDate.toString(),weekEndDate.toString());
            if(workTimesEntries.size()<1){
    
    
                continue;
            }
            //获取周报总结内容
            String weekData = "";
            // 创建标题行样式
            CellStyle titleCellStyle = workbook.createCellStyle();
            cellStyleSet(workbook, titleCellStyle);

            // 创建工作内容行样式
            CellStyle contentCellStyle = workbook.createCellStyle();
            workContentStyle(workbook, contentCellStyle);

            // 创建空行样式
            CellStyle blankCellStyle = workbook.createCellStyle();
            blankStyle(workbook, blankCellStyle);

            //筛选项目负责人
            List<String> projectManagerList = projectMembersEntries.stream().map(ProjectMembersEntry::getCreateBy).distinct().collect(Collectors.toList());
            for (String createBy : projectManagerList) {
    
    
                List<ProjectMembersEntry> collect = projectMembersEntries.stream().filter(entry -> entry.getCreateBy().equals(createBy)).collect(Collectors.toList());
                //对每个项目负责人负责的项目填充excel的标题
                ProjectMembersEntry projectMembersEntry = collect.get(0);
                String dept = projectMembersEntry.getDept();
                String projectManager = projectMembersEntry.getProjectManager();
                // 创建标题行
                Row titleRow = sheet.createRow(rowNumber);
                Cell titleRowCell1 = titleRow.createCell(0);
                titleRowCell1.setCellValue("姓名:");
                titleRowCell1.setCellStyle(titleCellStyle);

                Cell titleRowCell2 = titleRow.createCell(1);
                titleRowCell2.setCellValue(projectManager);
                titleRowCell2.setCellStyle(contentCellStyle);

                Cell titleRowCell3 = titleRow.createCell(2);
                titleRowCell3.setCellValue("部门:");
                titleRowCell3.setCellStyle(titleCellStyle);

                CellRangeAddress mergedRegion = new CellRangeAddress(rowNumber, rowNumber, 3, 4);
                sheet.addMergedRegion(mergedRegion);

                Cell titleRowCell4 = titleRow.createCell(3);
                titleRowCell4.setCellValue(dept);
                titleRowCell4.setCellStyle(contentCellStyle);
                Cell titleRowCell41 = titleRow.createCell(4);
                titleRowCell41.setCellStyle(titleCellStyle);

                Cell titleRowCell5 = titleRow.createCell(5);
                titleRowCell5.setCellValue("期间:");
                titleRowCell5.setCellStyle(titleCellStyle);

                // 合并startDatetime和endDatetime所在的三列
                CellRangeAddress mergedRegion2 = new CellRangeAddress(rowNumber, rowNumber, 6, 8);
                sheet.addMergedRegion(mergedRegion2);

                Cell titleRowCell6 = titleRow.createCell(6);
                titleRowCell6.setCellValue(weekStartDate + "至" + weekEndDate);
                titleRowCell6.setCellStyle(contentCellStyle);
                Cell titleRowCell7 = titleRow.createCell(7);
                titleRowCell7.setCellStyle(contentCellStyle);
                Cell titleRowCell8 = titleRow.createCell(8);
                titleRowCell8.setCellStyle(contentCellStyle);
                rowNumber++;
                // 创建第二层表头行
                // 设置列宽
                // 第一列宽度
                sheet.setColumnWidth(0, 25 * 256);
                sheet.setColumnWidth(1, 15 * 256);
                // 第二列宽度
                for (int i = 2; i <= 8; i++) {
    
    
                    // 剩下七列宽度
                    sheet.setColumnWidth(i, 10 * 256);
                }

                // 创建第二行标题
                Row titleRow1 = sheet.createRow(rowNumber);
                Cell titleCell = titleRow1.createCell(0);
                titleCell.setCellValue("所负责研发项目名称\n及项目编号");
                titleCell.setCellStyle(titleCellStyle);
                // 合并单元格,两行一列
                sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber+1, 0, 0));

                titleCell = titleRow1.createCell(1);
                titleCell.setCellValue("项目组成员");
                titleCell.setCellStyle(titleCellStyle);
                // 合并单元格,两行一列
                sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber+1, 1, 1));

                // 创建第三行标题
                titleCell = titleRow1.createCell(2);
                titleCell.setCellValue("工时明细");
                titleCell.setCellStyle(titleCellStyle);
                titleCell = titleRow1.createCell(8);
                titleCell.setCellStyle(titleCellStyle);
                // 合并单元格,一行七列
                sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 2, 8));

                rowNumber++;

                // 创建第三行子标题
                Row titleRow2 = sheet.createRow(rowNumber);
                String[] weekdays = {
    
    "周一", "周二", "周三", "周四", "周五", "周六", "周日"};
                Cell dayCell1 = titleRow2.createCell(0);
                dayCell1.setCellStyle(titleCellStyle);
                Cell dayCell2 = titleRow2.createCell(1);
                dayCell2.setCellStyle(titleCellStyle);
                for (int i = 2; i <= 8; i++) {
    
    
                    Cell dayCell = titleRow2.createCell(i);
                    dayCell.setCellValue(weekdays[i - 2]);
                    dayCell.setCellStyle(titleCellStyle);
                }

                rowNumber++;

                // 用于存储每周一到周日的工时合计
                String[] weekdayTotal = new String[7];
                for (int i = 0; i < 7; i++) {
    
    
                    weekdayTotal[i] = "0";
                }
                //项目Id的set集合
                Set<String> set = new HashSet<>();
                // 创建第三行内容
                for (ProjectMembersEntry membersEntry : collect) {
    
    
                    String projectId = membersEntry.getProjectId();
                    set.add(projectId);
                    String projectCode = membersEntry.getProjectCode();
                    String projectName = membersEntry.getProjectName();
                    String projectUserIds = membersEntry.getProjectUserIds();
                    String projectMembers = membersEntry.getProjectMembers();
                    if(StringUtils.isEmpty(projectUserIds)||StringUtils.isEmpty(projectMembers)){
    
    
                        continue;
                    }
                    String[] userIdSplit = projectUserIds.split(",");
                    String[] memberSplit = projectMembers.split(",");
                    int length = userIdSplit.length;
                    Row titleRow3 = sheet.createRow(rowNumber);
                    Cell titleCell3 = titleRow3.createCell(0);
                    titleCell3.setCellValue(projectName+"\n("+projectCode+")");
                    titleCell3.setCellStyle(contentCellStyle);
                    // 合并单元格,多行一列
                    if(length>1){
    
    
                        sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber+length-1, 0, 0));
                    }
                    int a=0,b=7;
                    //填充考勤工时
                    for (int i = 0; i < userIdSplit.length; i++){
    
    
                        String userId = userIdSplit[i];
                        String username = memberSplit[i];
                        List<WorkTimesEntry> workTimesEntryList = workTimesEntries.stream().filter(workTimesEntry -> workTimesEntry.getProjectId().equals(projectId))
                                .filter(workTimesEntry -> workTimesEntry.getUserId().equals(userId)).collect(Collectors.toList());
                        Row titleRows;
                        Cell cell;
                        if(i==0){
    
    
                            titleRows = titleRow3;
                        }else{
    
    
                            titleRows = sheet.createRow(rowNumber);
                            cell = titleRows.createCell(0);
                            cell.setCellStyle(contentCellStyle);
                        }
                        cell = titleRows.createCell(1);
                        cell.setCellValue(username);
                        cell.setCellStyle(contentCellStyle);
                        // 创建一个Map来跟踪每个星期几对应的已创建单元格的索引
                        Map<DayOfWeek, Integer> columnIndexMap = new HashMap<>();
                        for (DayOfWeek dayOfWeek : DayOfWeek.values()) {
    
    
                            columnIndexMap.put(dayOfWeek, -1);
                        }
                        //先设置该行的单元格格式
                        for (int j = a; j < b; j++) {
    
    
                            Cell timeCell = titleRows.createCell(j + 2);
                            timeCell.setCellStyle(contentCellStyle);
                        }
                        //填充工时内容
                        for (int j = a; j < b; j++) {
    
    
                            String actualityDuration = workTimesEntryList.size() < j + 1 ? "" : workTimesEntryList.get(j).getActualityDuration();
                            Date logDateTime = workTimesEntryList.size() < j + 1 ? null : workTimesEntryList.get(j).getLogDate();
                            // 默认列号,假设是周一
                            int columnIndex = j + 2;
                            LocalDate logDate = null;
                            try {
    
    
                                if (!Objects.isNull(logDateTime)) {
    
    
                            		// 解析logDate为LocalDate对象
                                    logDate = DateUtils.convertToLocalDate(logDateTime);
                                    // 获取logDate对应的星期几
                                    DayOfWeek dayOfWeek = logDate.getDayOfWeek();
                                    // 根据星期几来设置列号
                                    switch (dayOfWeek) {
    
    
                                        case MONDAY:
                                            columnIndex = j + 2;
                                            break;
                                        case TUESDAY:
                                            columnIndex = j + 3;
                                            break;
                                        case WEDNESDAY:
                                            columnIndex = j + 4;
                                            break;
                                        case THURSDAY:
                                            columnIndex = j + 5;
                                            break;
                                        case FRIDAY:
                                            columnIndex = j + 6;
                                            break;
                                        case SATURDAY:
                                            columnIndex = j + 7;
                                            break;
                                        case SUNDAY:
                                            columnIndex = j + 8;
                                            break;
                                    }

                                    // 累加每周一到周日的工时
                                    weekdayTotal[columnIndex - 2] = parseDuration(weekdayTotal[columnIndex - 2], actualityDuration);

                                    // 检查是否已经创建过该列对应的单元格,如果未创建,则创建新的单元格并存储索引
                                    int columnIndexMark = columnIndexMap.get(dayOfWeek);
                                    if (columnIndexMark == -1) {
    
    
                                        columnIndexMap.put(dayOfWeek, columnIndex);
                                    }

                                    Cell timeCell = titleRows.createCell(columnIndex);
                                    timeCell.setCellValue(actualityDuration);
                                    timeCell.setCellStyle(contentCellStyle);
                                }
                            } catch (DateTimeParseException e) {
    
    
                                // 异常处理:日期字符串格式不正确,可以抛出自定义异常或输出错误日志
                                throw new BusinessException("日期字符串格式不正确: " + logDate);
                            }
                        }
                        rowNumber++;
                    }
                }
                //添加合计行,计算项目负责人负责的所有项目每周一到周日的合计工时
                Row sumRow = sheet.createRow(rowNumber);
                Cell sumCell = sumRow.createCell(0);
                sumCell.setCellValue("合计");
                sumCell.setCellStyle(titleCellStyle);
                sumCell = sumRow.createCell(1);
                sumCell.setCellStyle(titleCellStyle);
                sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 0, 1));

                // 创建合计结果单元格
                for (int i = 2; i <= 8; i++) {
    
    
                    Cell dayCell = sumRow.createCell(i);
                    dayCell.setCellValue(weekdayTotal[i - 2]);
                    dayCell.setCellStyle(titleCellStyle);
                }
                //周报总结汇总
                LambdaQueryWrapper<StWeekLog> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.between(StWeekLog::getLogStartTime,weekStartDate,weekEndDate)
                        .in(StWeekLog::getProjectId,set);
                List<StWeekLog> stWeekLogList = stWeekLogMapper.selectList(queryWrapper);
                if(stWeekLogList.size()>0){
    
    
                    for (StWeekLog stWeekLog : stWeekLogList) {
    
    
                        if(StringUtils.isEmpty(weekData)){
    
    
                            weekData = stWeekLog.getWeekDesc();
                        }else{
    
    
                            weekData += "。\n"+stWeekLog.getWeekDesc();
                        }
                    }
                }
                rowNumber++;

                //添加本周项目执行情况总结行
                Row weekExecRow = sheet.createRow(rowNumber);
                Cell weekExecCell = weekExecRow.createCell(0);
                weekExecCell.setCellValue("本周项目执行情况总结");
                weekExecCell.setCellStyle(titleCellStyle);
                weekExecCell = weekExecRow.createCell(1);
                weekExecCell.setCellValue(weekData);
                weekExecCell.setCellStyle(contentCellStyle);
                sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 2, 0, 0));
                // 合并三行八列的单元格
                sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 2, 1, 8));
                // 创建执行情况总结内容(三行八列合并)
                for (int n = 2; n <= 8; n++) {
    
    
                    Cell timeCell = weekExecRow.createCell(n);
                    timeCell.setCellStyle(contentCellStyle);
                }
                rowNumber++;
                Row weekExecRow1 = sheet.createRow(rowNumber);
                for (int n = 0; n <= 8; n++) {
    
    
                    Cell timeCell = weekExecRow1.createCell(n);
                    timeCell.setCellStyle(contentCellStyle);
                }
                rowNumber++;
                Row weekExecRow2 = sheet.createRow(rowNumber);
                for (int n = 0; n <= 8; n++) {
    
    
                    Cell timeCell = weekExecRow2.createCell(n);
                    timeCell.setCellStyle(contentCellStyle);
                }
                rowNumber++;

                //添加两个空行
                for (int i = 0; i < 2; i++) {
    
    
                    Row blankRow = sheet.createRow(rowNumber);
                    blankRow.createCell(0).setCellValue("");
                    // 合并空行的9列单元格
                    sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 0, 8));
                    rowNumber++; // 增加行号
                }
            }
        }

        try {
    
    
            // 保存Excel文件
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    new String(("周报_"+startDatetime+"-"+endDatetime).getBytes(), "ISO8859-1") + ".xlsx");
            workbook.write(response.getOutputStream());
            workbook.close();
            response.getOutputStream().close();
        } catch (IOException e) {
    
    
            throw new BusinessException(e.getMessage());
        }
    }

4. Encapsulated functions

   /**
     * 空行风格
     *
     * @param workbook       工作簿
     * @param blankCellStyle 空白单元格样式
     * @author yangz
     * @date 2023/07/20
     */
    private static void blankStyle(Workbook workbook, CellStyle blankCellStyle) {
    
    
        Font blankFont = workbook.createFont();
        blankCellStyle.setFont(blankFont);
        blankCellStyle.setBorderTop(BorderStyle.THICK);
        blankCellStyle.setBorderBottom(BorderStyle.THICK);
    }

    /**
     * 工作内容样式
     *
     * @param workbook         工作簿
     * @param contentCellStyle 内容单元格样式
     * @author yangz
     * @date 2023/07/20
     */
    private static void workContentStyle(Workbook workbook, CellStyle contentCellStyle) {
    
    
        Font contentFont = workbook.createFont();
        contentFont.setBold(false);
        contentCellStyle.setFont(contentFont);
        contentCellStyle.setWrapText(true);
        contentCellStyle.setAlignment(HorizontalAlignment.CENTER);
        contentCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        contentCellStyle.setBorderTop(BorderStyle.THICK);
        contentCellStyle.setBorderBottom(BorderStyle.THICK);
        contentCellStyle.setBorderLeft(BorderStyle.THICK);
        contentCellStyle.setBorderRight(BorderStyle.THICK);
    }
    /**
     * 标题单元格样式设置
     *
     * @param workbook         工作簿
     * @param projectCellStyle 项目单元格样式
     * @return {@link CellStyle }
     * @author yangz
     * @date 2023/07/19
     */
    private static CellStyle cellStyleSet(Workbook workbook, CellStyle projectCellStyle) {
    
    
        Font projectFont = workbook.createFont();
        projectFont.setBold(true);
        projectCellStyle.setFont(projectFont);
        projectCellStyle.setWrapText(true);
        projectCellStyle.setAlignment(HorizontalAlignment.CENTER);
        projectCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        projectCellStyle.setBorderTop(BorderStyle.THICK);
        projectCellStyle.setBorderBottom(BorderStyle.THICK);
        projectCellStyle.setBorderLeft(BorderStyle.THICK);
        projectCellStyle.setBorderRight(BorderStyle.THICK);
        return projectCellStyle;
    }
	/**
     * 校验时间
     *
     * @param startDate 开始日期时间
     * @param endDate   结束日期时间
     * @author yangz
     * @date 2023/07/21
     */
    public void validateDateRange(LocalDate startDate, LocalDate endDate) {
    
    
        if (startDate == null || endDate == null || startDate.isAfter(endDate)) {
    
    
            throw new IllegalArgumentException("开始日期和结束日期不能为空,且开始日期必须早于或等于结束日期");
        }

        long weekSpan = ChronoUnit.DAYS.between(startDate, endDate);
        if (weekSpan < MIN_WEEK_SPAN) {
    
    
            throw new IllegalArgumentException("开始日期和结束日期的时间跨度必须大于一周");
        }
    }

5. Week Utils

import javafx.util.Pair;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

/**
 * 星期实效
 *
 * @author yangz
 * @date 2023/07/21
 */
public class DayOfWeekUtil {
    
    

    /**
     * 得到一天星期
     *
     * @param date 日期
     * @return {@link String }
     * @author yangz
     * @date 2023/07/21
     */
    public static String getDayOfWeek(LocalDate date) {
    
    
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        switch (dayOfWeek) {
    
    
            case MONDAY:
                return "星期一";
            case TUESDAY:
                return "星期二";
            case WEDNESDAY:
                return "星期三";
            case THURSDAY:
                return "星期四";
            case FRIDAY:
                return "星期五";
            case SATURDAY:
                return "星期六";
            case SUNDAY:
                return "星期日";
            default:
                return "未知";
        }
    }

    /**
     * 周得到整数一天
     *
     * @param date 日期
     * @return {@link Integer }
     * @author yangz
     * @date 2023/07/21
     */
    public static Integer getIntDayOfWeek(LocalDate date) {
    
    
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        switch (dayOfWeek) {
    
    
            case MONDAY:
                return 1;
            case TUESDAY:
                return 2;
            case WEDNESDAY:
                return 3;
            case THURSDAY:
                return 4;
            case FRIDAY:
                return 5;
            case SATURDAY:
                return 6;
            case SUNDAY:
                return 7;
            default:
                return null;
        }
    }

    /**
     * 分割时间一周
     *
     * @param startDatetime 开始日期时间
     * @param endDatetime   结束日期时间
     * @author yangz
     * @date 2023/07/21
     */
    public static List<Pair<LocalDate, LocalDate>> splitTimeByWeek(LocalDate startDatetime, LocalDate endDatetime) {
    
    
        List<Pair<LocalDate, LocalDate>> weeks = new ArrayList<>();

        LocalDate currentStart = startDatetime;
        LocalDate currentEnd = startDatetime.plusDays(6);

        while (!currentEnd.isAfter(endDatetime)) {
    
    
            weeks.add(new Pair<>(currentStart, currentEnd));
            currentStart = currentEnd.plusDays(1);
            currentEnd = currentStart.plusDays(6);
        }

        if (!currentStart.isAfter(endDatetime)) {
    
    
            weeks.add(new Pair<>(currentStart, endDatetime));
        }

        return weeks;
    }


    public static void main(String[] args) {
    
    
        LocalDate date = LocalDate.of(2023, 7, 20);
        String dayOfWeek = getDayOfWeek(date);
        System.out.println("2023-07-20 是:" + dayOfWeek);
        System.out.println("2023-07-20 是:" + getIntDayOfWeek(date));
    }
}

6. Using this weekly reporting tool is very simple:

  1. Call the exportWeekReportToExcel method in the Java code and pass in the correct parameters: HttpServletResponse, startDatetime, and endDatetime.
  2. After completing the data query and generating an Excel table, the tool will automatically provide the generated Excel file to the user for download.

7. Excel result display

insert image description here

Summarize

This weekly report reporting tool makes the filling and management of weekly reports more efficient and convenient. It not only reduces the workload of manual operations, but also greatly reduces the error rate of data processing and export. Hope this tool can help your project management and team collaboration!

Conclusion: Learn the benevolence, righteousness, propriety, wisdom and trustworthiness of Confucius and Mencius in school, and learn the way of villains from Lao Tzu in society

Guess you like

Origin blog.csdn.net/Da_zhenzai/article/details/131937829