美文网首页程序员SpringBoot精选CMS管理系统的开发和应用
【Java代码生成器】SpringBoot、SSM代码生成器功能

【Java代码生成器】SpringBoot、SSM代码生成器功能

作者: 小螺旋丸 | 来源:发表于2020-03-24 15:33 被阅读0次

    引言

      代码生成器一直有在断断续续的更新,只是由于时间关系没能一直坚持写博客,但每天依然有朋友前去下载关注,对此我感到十分荣幸,源码已经全部开放至码云,感兴趣的朋友可以去文末链接自行提取查看,同时今天更新了几个小功能,让我们一起看一下吧。

    全局异常处理

      增加了全局异常处理模板:allExceptionHandler.ftl,代码很简单,相信熟悉SpringBoot的朋友一眼就能看明白:

    package ${packageName}.config;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.ResponseStatus;
    
    @ControllerAdvice
    @ResponseBody
    public class AllExceptionHandler {
    
        private static final Logger logger = LoggerFactory.getLogger(AllExceptionHandler.class);
    
        @ExceptionHandler(Exception.class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        public String handlerUnexcptedServer(Exception ex) {
            logger.error("发生系统异常,错误信息为:" + ex.getMessage());
            return "系统异常,请去后台查看!";
        }
    }
    
    

      这里直接捕获了Exception类,如果controller中的方法发生了异常,会统一运行到此处进行相应的处理,原理不必多说:AOP,只不过Spirng已经帮助我们实现了,直接拿来用即可,这里所做的处理很简单:打印错误信息,返回错误响应。生成代码之后大家可以根据需要自由扩展。

    日志切面

      日志对于一个系统来说是十分重要的,大多数情况下,我们需要在执行方法的时候打印一些必要的日志,比如当前执行的方法,执行方法所需要的时间,或者在方法运行完毕后保存信息等。。。
      对于日志的处理,当然需要抽离出去,否则代码将变得十分冗余,这个时候同样需要使用AOP,自定义日志切面类,实现个性化的日志处理操作,代码如下:

    package ${packageName}.config;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class LogAopAspect {
    
        private static final Logger logger = LoggerFactory.getLogger(LogAopAspect.class);
    
    
        @Around("execution(* ${packageName}.controller.*.*(..))")
        public Object process(ProceedingJoinPoint pjp) throws Throwable {
    
            Class<?> currentClass = pjp.getTarget().getClass();
            MethodSignature signature = (MethodSignature) (pjp.getSignature());
            String ClassName = currentClass.getSimpleName();
            String methodName = currentClass.getMethod(signature.getName(), signature.getParameterTypes()).getName();
            logger.info("======= 开始执行:" + ClassName + " — " + methodName + " ========");
            Object obj = pjp.proceed();
            logger.info("======= 执行结束:" + ClassName + " — " + methodName + " ========");
            return obj;
    
        }
    
    
    }
    
    

      这里使用了Spirng的环绕通知,根据切入点表达式,Spring会扫描controller包下的所有类,生成相应的代理类,添加相关操作,此处只是在方法执行前和执行后打印了相关的类名信息,这样一来,如果程序出现问题,可以帮我们迅速找到错误位置,提高系统的可维护性。

    日志工具类

      增加了日志工具类模板:loggerUtil.ftl,主要用来方便输出日志和日常调试,代码如下:

    package ${packageName}.utils;
    
    import org.slf4j.LoggerFactory;
    
    /**
     * 日志工具类,使用静态方法打印日志  无需每个类中定义日志对象
     * Logback对每个Logger对象做了缓存,每次调用LoggerFactory.getLogger(String name)时如果已存在则从缓存中获取不会生成新的对象;
     * 同时也不会有对象的创建与销毁造成的性能损失
     */
    public class LoggerUtil {
    
        public static void error(String msg) {
            LoggerFactory.getLogger(getClassName()).error(msg);
        }
    
        public static void error(String msg, Object... obj) {
            LoggerFactory.getLogger(getClassName()).error(msg, obj);
        }
    
        public static void warn(String msg) {
            LoggerFactory.getLogger(getClassName()).error(msg);
        }
    
        public static void warn(String msg, Object... obj) {
            LoggerFactory.getLogger(getClassName()).error(msg, obj);
        }
    
        public static void info(String msg) {
            LoggerFactory.getLogger(getClassName()).info(msg);
        }
    
        public static void info(String msg, Object... obj) {
            LoggerFactory.getLogger(getClassName()).info(msg, obj);
        }
    
        public static void debug(String msg) {
            LoggerFactory.getLogger(getClassName()).debug(msg);
        }
    
        public static void debug(String msg, Object... obj) {
            LoggerFactory.getLogger(getClassName()).debug(msg, obj);
        }
    
        // 获取调用 error,info,debug静态类的类名
        private static String getClassName() {
            return new SecurityManager() {
                public String getClassName() {
                    return getClassContext()[3].getName();
                }
            }.getClassName();
        }
    }
    
    

      这个没有什么可讲的,其中getClassName方法通过返回当前执行堆栈的数组来获取当前调用此方法的类名,索引3处为我们需要获取的类名。

    excelUtil扩展

      对excelUtil.ftl模板做了进一步扩展,增加了一些较为实用的方法,使用简单,代码如下:

    private static final String XLS = "xls";
        private static final String XLSX = "xlsx";
    
        public static CellStyle creatCellStyle(SXSSFWorkbook workbook, boolean head) {
            CellStyle style = workbook.createCellStyle();
            //对齐方式设置
            style.setAlignment(HorizontalAlignment.CENTER);
            style.setBorderBottom(BorderStyle.THIN);
            style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框
            style.setBorderLeft(BorderStyle.THIN);
            style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框
            style.setBorderRight(BorderStyle.THIN);
            style.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框
            style.setBorderTop(BorderStyle.THIN);
            style.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框
            style.setWrapText(true);// 设置自动换行
            if (head) {
                //设置背景颜色
                style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
                style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                //粗体字设置
                Font font = workbook.createFont();
                font.setBold(true);
                style.setFont(font);
            }
            return style;
        }
    
    /**
         * 根据文件后缀名类型获取对应的工作簿对象
         *
         * @param inputStream 读取文件的输入流
         * @param fileType    文件后缀名类型(xls或xlsx)
         * @return 包含文件数据的工作簿对象
         * @throws IOException
         */
        public static Workbook getWorkbook(InputStream inputStream, String fileType) throws IOException {
            Workbook workbook = null;
            if (fileType.equalsIgnoreCase(XLS)) {
                workbook = new HSSFWorkbook(inputStream);
            } else if (fileType.equalsIgnoreCase(XLSX)) {
                workbook = new XSSFWorkbook(inputStream);
            }
            return workbook;
        }
    
    
        /**
         * 读取Excel文件内容 每一行内容使用Map封装
         *
         * @param fileName 要读取的Excel文件所在路径
         * @return 读取结果列表,读取失败时返回null
         */
        public static List<Map<String, String>> readExcelToRowMap(String fileName) {
    
            // 读取excel中的数据
            Map<String, String> map = new LinkedHashMap<>();
            List<Map<String, String>> resultDataList = parseExcel(readExcel(fileName), map);
    
            return resultDataList;
    
        }
    
        public static List<Map<String, String>> readExcelToRowMap(File file) {
    
            // 读取excel中的数据
            Map<String, String> map = new LinkedHashMap<>();
            List<Map<String, String>> resultDataList = parseExcel(readExcel(file), map);
    
            return resultDataList;
    
        }
    
        /**
         * 读取Excel文件内容 每一行内容使用List封装
         *
         * @param fileName 要读取的Excel文件所在路径
         * @return 读取结果列表,读取失败时返回null
         */
        public static List<List<String>> readExcelToRowList(String fileName) {
    
            // 读取excel中的数据
            List<String> list = new ArrayList<>();
            List<List<String>> resultDataList = parseExcel(readExcel(fileName), list);
    
            return resultDataList;
    
        }
    
        public static List<List<String>> readExcelToRowList(File file) {
    
            // 读取excel中的数据
            List<String> list = new ArrayList<>();
            List<List<String>> resultDataList = parseExcel(readExcel(file), list);
    
            return resultDataList;
    
        }
    
        /**
         * 读取excel获得workbook
         *
         * @param e
         * @return
         */
        private static <E> Workbook readExcel(E e) {
    
            Workbook workbook = null;
            FileInputStream inputStream = null;
    
            try {
    
                String fileName = "";
                String fileType = "";
                File excelFile = null;
                if (e instanceof String) {
                    // 获取Excel后缀名
                    fileName = (String) e;
                    fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
                    // 获取Excel文件
                    excelFile = new File(fileName);
                    if (!excelFile.exists()) {
                        return null;
                    }
                    inputStream = new FileInputStream(excelFile);
                    workbook = getWorkbook(inputStream, fileType);
                } else if (e instanceof File) {
                    fileName = ((File) e).getName();
                    fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
                    // 获取Excel工作簿
                    inputStream = new FileInputStream((File) e);
                    workbook = getWorkbook(inputStream, fileType);
                }
                return workbook;
            } catch (Exception e1) {
                e1.printStackTrace();
                return null;
            } finally {
                try {
                    if (null != workbook) {
                        workbook.close();
                    }
                    if (null != inputStream) {
                        inputStream.close();
                    }
                } catch (Exception e2) {
                    return null;
                }
            }
        }
    
    
        /**
         * 解析Excel数据
         *
         * @param workbook Excel工作簿对象
         * @return 解析结果
         */
        private static <E> List<E> parseExcel(Workbook workbook, E e) {
    
            if (workbook == null) {
                return null;
            }
    
            List<E> resultDataList = new ArrayList<>();
            // 解析sheet
            for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
                Sheet sheet = workbook.getSheetAt(sheetNum);
                // 校验sheet是否合法
                if (sheet == null) {
                    continue;
                }
                // 获取第一行数据
                int firstRowNum = sheet.getFirstRowNum();
                Row firstRow = sheet.getRow(firstRowNum);
                if (null == firstRow) {
                    System.out.println(sheet.getSheetName() + "无数据");
                    continue;
                }
    
                //获取head头部
                Row headRow = sheet.getRow(firstRowNum);
                //获取列数
                int numberOfCells = headRow.getPhysicalNumberOfCells();
    
                List<String> headList = new ArrayList<>();
                for (int i = 0; i < numberOfCells; i++) {
                    Cell cell = headRow.getCell(i);
                    String head = convertCellValueToString(cell);
                    headList.add(head);
                }
                // 解析每一行的数据,构造数据对象
                int rowStart = firstRowNum + 1;
    
                int rowEnd = sheet.getPhysicalNumberOfRows();
                for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
                    Row row = sheet.getRow(rowNum);
    
                    if (null == row) {
                        continue;
                    }
    
                    E resultData = null;
                    if (e instanceof Map) {
                        resultData = (E) convertRowToDataMap(row, headList);
                    } else {
                        resultData = (E) convertRowToDataList(row, headList);
                    }
    
                    if (null == resultData) {
                        continue;
                    }
                    resultDataList.add(resultData);
                }
    
            }
    
            return resultDataList;
        }
    
    
        /**
         * 将单元格内容转换为字符串
         *
         * @param cell
         * @return
         */
    
        private static String convertCellValueToString(Cell cell) {
            if (cell == null) {
                return "";
            }
            String returnValue = "";
            switch (cell.getCellType()) {
                case NUMERIC:   //数字
                    if (DateUtil.isCellDateFormatted(cell)) {
                        Date date = cell.getDateCellValue();
                        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// HH:mm:ss cellValue = df2.format(d);
                        returnValue = format.format(date);
                    } else {
                        Double doubleValue = cell.getNumericCellValue();
                        // 格式化科学计数法,取一位整数
                        DecimalFormat df = new DecimalFormat("0");
                        returnValue = df.format(doubleValue);
                    }
                    break;
                case STRING:    //字符串
                    returnValue = cell.getStringCellValue();
                    break;
                case BOOLEAN:   //布尔
                    Boolean booleanValue = cell.getBooleanCellValue();
                    returnValue = booleanValue.toString();
                    break;
                case BLANK:     // 空值
                    break;
                case FORMULA:   // 公式
                    returnValue = cell.getCellFormula();
                    break;
                case ERROR:     // 故障
                    break;
                default:
                    break;
            }
            return returnValue;
        }
    
        /**
         * 提取每一行中需要的数据到map中
         *
         * @param row 行数据
         * @return 解析后的行数据对象
         */
        private static Map<String, String> convertRowToDataMap(Row row, List<String> headList) {
    
            Map<String, String> resultData = new LinkedHashMap<>();
    
            for (int i = 0; i < headList.size(); i++) {
                Cell cell = row.getCell(i);
                String data = convertCellValueToString(cell);
                resultData.put(headList.get(i), data);
            }
    
            return resultData;
    
        }
    
        /**
         * 提取每一行中需要的数据到List中
         *
         * @param row 行数据
         * @return 解析后的行数据对象
         */
        private static List<String> convertRowToDataList(Row row, List<String> headList) {
    
            List<String> resultData = new ArrayList<>();
    
    
            for (int i = 0; i < headList.size(); i++) {
                Cell cell = row.getCell(i);
                String data = convertCellValueToString(cell);
                resultData.add(data);
            }
    
            return resultData;
    
        }
    

    返回值日期格式化处理

      对于响应返回值的日期类型做了格式化的处理,在SpringBoot中增加了如下配置:

    spring:
        jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8
    

    SSM中增加如下配置:

    <mvc:annotation-driven>
            <mvc:message-converters>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                    <property name="objectMapper">
                        <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                            <property name="dateFormat">
                                <bean class="java.text.SimpleDateFormat">
                                    <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />
                                </bean>
                            </property>
                        </bean>
                    </property>
                </bean>
            </mvc:message-converters>
        </mvc:annotation-driven>
    

      现在生成器会自动加入此配置。

    源码全开放

      代码生成器的源码已经全部开放,感兴趣的朋友可以去码云查看,readme中有具体的源码解读,地址为:https://gitee.com/zrxjava/codeMan,感谢您的阅读,下次再见!

    相关文章

      网友评论

        本文标题:【Java代码生成器】SpringBoot、SSM代码生成器功能

        本文链接:https://www.haomeiwen.com/subject/mxgoyhtx.html