fieldNames = new ArrayList<>();
+
+ final Field[] declaredFields = data.get(0).getClass().getDeclaredFields();
+ final XSSFCellStyle defaultStyle = createDefaultDataStyle(workbook);
+
+ int j = 0;
+ for (Field declaredField : declaredFields) {
+ final ExportField annotation = declaredField.getAnnotation(ExportField.class);
+ if (annotation == null) {
+ continue;
+ }
+ fieldNames.add(annotation.name());
+
+ XSSFCell cell = getCell(sheet, 0, j);
+ cell.setCellValue(annotation.name());
+ cell.setCellStyle(defaultStyle);
+
+ int colWidth = Integer.max(annotation.width(), fieldNames.get(j).length());
+ if (annotation.type() == ExportType.DATE) {
+ colWidth = annotation.timeFormat().length() / 2;
+ }
+
+ double t = (colWidth * 2 + 2) * 256;
+ if (t > 255 * 256) {
+ t = 20 * 256;
+ }
+ sheet.setColumnWidth(j, (int) t);
+ j++;
+ }
+
+ for (int row = 0; row < data.size(); row++) {
+ final Object bean = data.get(row);
+
+ int col = 0;
+
+ for (int fieldCol = 0; fieldCol < declaredFields.length; fieldCol++) {
+ final Field declaredField = declaredFields[fieldCol];
+ final ExportField[] annotation = declaredField.getAnnotationsByType(ExportField.class);
+ if (annotation == null || annotation.length == 0) {
+ continue;
+ }
+ String property = "";
+ XSSFCell cell = getCell(sheet, row + 1, col++);
+ switch (annotation[0].type()) {
+ case DATE:
+ String format = annotation[0].timeFormat();
+ if (format.equals("")) {
+ format = "yyyy-MM-dd HH:mm:ss";
+ }
+ final CellStyle dateStyle = getCellDateStyle(workbook, format);
+ //fix : null point ex
+ if (PropertyUtils.getProperty(bean, declaredField.getName()) == null) {
+ cell.setCellStyle(dateStyle);
+ break;
+ }
+ Long timeMills = null;
+ if (declaredField.getType().equals(Timestamp.class)) {
+ Timestamp obj = (Timestamp) PropertyUtils.getProperty(bean, declaredField.getName());
+ timeMills = obj.getTime();
+ }
+ if (declaredField.getType().equals(Date.class)) {
+ Date obj = (Date) PropertyUtils.getProperty(bean, declaredField.getName());
+ timeMills = obj.getTime();
+ }
+ if (declaredField.getType().equals(DateTime.class)) {
+ DateTime obj = (DateTime) PropertyUtils.getProperty(bean, declaredField.getName());
+ timeMills = obj.getMillis();
+ }
+ if (declaredField.getType().equals(Long.class)) {
+ Long obj = (Long) PropertyUtils.getProperty(bean, declaredField.getName());
+ timeMills = obj;
+ }
+ if (declaredField.getType().equals(Integer.class)) {
+ Integer obj = (Integer) PropertyUtils.getProperty(bean, declaredField.getName());
+ timeMills = obj.longValue() * 1000;
+ }
+ final String pattern = annotation[0].timeFormat();
+ DateTime dateTime = new DateTime(timeMills, DateTimeZone.forID(timeZone));
+ DateTime dateTime1 = DateTime.parse(dateTime.toString(pattern), DateTimeFormat.forPattern(pattern));
+ cell.setCellStyle(dateStyle);
+ cell.setCellValue(dateTime1.toDate());
+ break;
+ case NUMBER:
+ Number number = (Number) PropertyUtils.getProperty(bean, declaredField.getName());
+ if (number == null) {
+ break;
+ }
+ double v = 0;
+ if (number != null) {
+ v = NumberUtils.toDouble(number.toString());
+ }
+ cell.setCellValue(v);
+ cell.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell.setCellStyle(defaultStyle);
+ break;
+ default:
+ cell.setCellStyle(defaultStyle);
+ String name = declaredField.getName();
+ if (name.equals("pId")) {
+ name = "PId";
+ }
+ if (name.equals("pMobile")) {
+ name = "PMobile";
+ }
+ property = BeanUtils.getProperty(bean, name);
+ cell.setCellValue(property);
+ break;
+ }
+ }
+ }
+
+ //设置行高
+ sheet.setDefaultRowHeightInPoints(15);
+ // 冻结第一行
+ sheet.createFreezePane(0, 1);
+ workbook.write(outputStream);
+ workbook.close();
+ }
+
+ public static String getCellValue(Cell cell) {
+ String cellValue = null;
+ int cellType = cell.getCellType();
+ switch (cellType) {
+ case Cell.CELL_TYPE_STRING: // 字符串型
+ cellValue = cell.getRichStringCellValue().getString();
+ break;
+ case Cell.CELL_TYPE_NUMERIC: // 数值型 (纯数字类型如果 cell.getNumericCellValue(),读取的类型是double,需要做特殊的处理)
+ if (DateUtil.isCellDateFormatted(cell)) { // 时间类型
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ Date date = cell.getDateCellValue();
+ if (date != null) {
+ cellValue = String.valueOf(dateFormat.format(date));
+ }
+ } else {
+ // 小数点后面是否只包含0,如果是则化整,不是则默认
+ cell.setCellType(Cell.CELL_TYPE_STRING);
+ String temp = cell.getRichStringCellValue().getString();
+ if (temp.contains(".")) {
+ String temp1 = temp.substring(temp.indexOf(".") + 1, temp.length());
+ if (!temp1.isEmpty()) {
+ if (temp1.matches("0+$")) {
+ cellValue = temp.substring(0, temp.indexOf("."));
+ } else {
+ cellValue = temp;
+ }
+ }
+ } else {
+ cellValue = temp;
+ }
+ }
+ break;
+ case Cell.CELL_TYPE_FORMULA:
+ String temp = cell.getCellFormula();
+ if (null != temp) {
+ cellValue = temp.replaceAll("#N/A", "").trim();
+ }
+ break;
+ case Cell.CELL_TYPE_ERROR: // 故障
+ cellValue = null;
+ break;
+ case Cell.CELL_TYPE_BOOLEAN:
+ cellValue = Boolean.toString(cell.getBooleanCellValue());
+ break;
+ case Cell.CELL_TYPE_BLANK: // 空值
+ cellValue = null;
+ break;
+ default:
+ cellValue = "";
+ }
+ return cellValue;
+ }
+
+
+ private static CellStyle getCellDateStyle(XSSFWorkbook workbook, String pattern) {
+
+ XSSFDataFormat format = workbook.createDataFormat();
+
+ CellStyle cellStyle = workbook.createCellStyle();
+ cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
+ cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); //左边框
+ cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN); //右边框
+ cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN); //上边框
+ cellStyle.setDataFormat(format.getFormat(pattern));
+
+ cellStyle.setVerticalAlignment(HSSFCellStyle.ALIGN_CENTER);
+ return cellStyle;
+ }
+
+ //自定义的方法,插入某个图片到指定索引的位置
+ private static void insertImage(XSSFWorkbook wb, XSSFDrawing pa, byte[] data, int row, int column) {
+ XSSFClientAnchor anchor = new XSSFClientAnchor();
+ anchor.setCol1(column);
+ anchor.setCol2(column + 1);
+ anchor.setRow1(row);
+ anchor.setRow2(row + 1);
+ anchor.setAnchorType(2);
+ pa.createPicture(anchor, wb.addPicture(data, XSSFWorkbook.PICTURE_TYPE_JPEG));
+ }
+
+ //从图片里面得到字节数组
+ private static byte[] getImageData(BufferedImage bi) {
+ try {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ ImageIO.write(bi, "JPG", bout);
+ return bout.toByteArray();
+ } catch (Exception exe) {
+ LOGGER.error("IO Exception", exe);
+ return null;
+ }
+ }
+
+
+ /**
+ * Convenient method to obtain the cell in the given sheet, row and column. Creates the row and the cell if they
+ * still doesn't already exist. Thus, the column can be passed as an int, the method making the needed downcasts.
+ *
+ * @param sheet a sheet object. The first sheet is usually obtained by workbook.getSheetAt(0)
+ * @param row thr row number
+ * @param col the column number
+ * @return the HSSFCell
+ */
+ private static XSSFCell getCell(XSSFSheet sheet, int row, int col) {
+ XSSFRow sheetRow = sheet.getRow(row);
+ if (sheetRow == null) {
+ sheetRow = sheet.createRow(row);
+ }
+ XSSFCell cell = sheetRow.getCell(col);
+ if (cell == null) {
+ cell = sheetRow.createCell(col);
+ }
+ return cell;
+ }
+
+ /**
+ * 设置缺省标题样式
+ */
+ private static XSSFCellStyle getTitleStyle(XSSFWorkbook workbook) {
+ XSSFCellStyle style = workbook.createCellStyle();
+ style.setFillForegroundColor(HSSFColor.WHITE.index);
+ style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
+ style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
+ style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
+ style.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
+ style.setBorderLeft(HSSFCellStyle.BORDER_THIN); //左边框
+ style.setBorderRight(HSSFCellStyle.BORDER_THIN); //右边框
+ style.setBorderTop(HSSFCellStyle.BORDER_THIN); //上边框
+ style.setLeftBorderColor(HSSFColor.BLACK.index);
+ style.setRightBorderColor(HSSFColor.BLACK.index);
+ style.setTopBorderColor(HSSFColor.BLACK.index);
+ style.setBottomBorderColor(HSSFColor.BLACK.index);
+
+ //设置单元格字体显示颜色
+ XSSFFont font = workbook.createFont();//创建一个Font
+ font.setFontName("黑体");
+ font.setFontHeightInPoints((short) 14);
+ font.setColor(HSSFColor.BLACK.index);
+ style.setFont(font);
+ return style;
+ }
+
+ /**
+ * 设置缺省普通单元格样式
+ */
+ private static XSSFCellStyle createDefaultDataStyle(XSSFWorkbook workbook) {
+ XSSFCellStyle style = workbook.createCellStyle();
+ style.setFillForegroundColor(HSSFColor.WHITE.index);
+ style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
+ style.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
+ style.setBorderLeft(HSSFCellStyle.BORDER_THIN); //左边框
+ style.setBorderRight(HSSFCellStyle.BORDER_THIN); //右边框
+ style.setBorderTop(HSSFCellStyle.BORDER_THIN); //上边框
+ //style.setWrapText(true);
+ //设置单元格字体显示颜色
+ XSSFFont font = workbook.createFont();//创建一个Font
+ font.setFontName("宋体");
+ font.setFontHeightInPoints((short) 10);
+ font.setColor(HSSFColor.BLACK.index);
+ style.setFont(font);
+ return style;
+ }
+}
+
diff --git a/alive-commons/src/main/java/com/alive/commons/excel/ExportField.java b/alive-commons/src/main/java/com/alive/commons/excel/ExportField.java
new file mode 100644
index 0000000..c17f230
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/excel/ExportField.java
@@ -0,0 +1,22 @@
+package com.alive.commons.excel;
+
+import java.lang.annotation.*;
+
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExportField {
+ /*表头显示名称*/
+ String name();
+
+ /*导出数据的类型*/
+ ExportType type() default ExportType.STRING;
+
+ /*导出数据的格式*/
+ String timeFormat() default "yyyy-MM-dd HH:mm:ss";
+
+ String stringFormat() default "";
+
+ //默认列宽
+ int width() default 5;
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/excel/ExportModel.java b/alive-commons/src/main/java/com/alive/commons/excel/ExportModel.java
new file mode 100644
index 0000000..93af194
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/excel/ExportModel.java
@@ -0,0 +1,14 @@
+package com.alive.commons.excel;
+
+import java.util.Collections;
+import java.util.Map;
+
+public interface ExportModel {
+ default String getSheetName() {
+ return "sheet1";
+ }
+
+ default Map getExtAttr() {
+ return Collections.emptyMap();
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/excel/ExportType.java b/alive-commons/src/main/java/com/alive/commons/excel/ExportType.java
new file mode 100644
index 0000000..6b830ac
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/excel/ExportType.java
@@ -0,0 +1,10 @@
+package com.alive.commons.excel;
+
+public enum ExportType {
+ /*日期类型*/
+ DATE,
+ /*字符串*/
+ STRING,
+ /*数字*/
+ NUMBER
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/exception/DcException.java b/alive-commons/src/main/java/com/alive/commons/exception/DcException.java
new file mode 100644
index 0000000..3e18a01
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/exception/DcException.java
@@ -0,0 +1,39 @@
+package com.alive.commons.exception;
+
+import com.alive.commons.enums.BaseEnum;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Map;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DcException extends RuntimeException {
+
+ private int code;
+
+ private BaseEnum resultCodeEnum;
+
+ private Map otherInfo;
+
+ public DcException(BaseEnum codeEnum) {
+ super(codeEnum.i18nKey());
+ resultCodeEnum = codeEnum;
+ code = codeEnum.getEnumCode();
+ }
+
+ public DcException(BaseEnum codeEnum, Map otherInfo) {
+ super(codeEnum.i18nKey());
+ resultCodeEnum = codeEnum;
+ this.code = codeEnum.getEnumCode();
+ this.otherInfo = otherInfo;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public BaseEnum getResultCodeEnum() {
+ return resultCodeEnum;
+ }
+}
\ No newline at end of file
diff --git a/alive-commons/src/main/java/com/alive/commons/exception/ErrorHandler.java b/alive-commons/src/main/java/com/alive/commons/exception/ErrorHandler.java
new file mode 100644
index 0000000..2262e1f
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/exception/ErrorHandler.java
@@ -0,0 +1,87 @@
+package com.alive.commons.exception;
+
+import com.alive.commons.model.BaseResult;
+import com.alive.commons.util.MessageUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import springfox.documentation.annotations.ApiIgnore;
+
+@Slf4j
+@ControllerAdvice
+@ApiIgnore
+public class ErrorHandler {
+
+ @ResponseBody
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity> handleException(Exception e) {
+ log.error(">>> Exception 请处理: {}", e.getLocalizedMessage());
+ e.printStackTrace();
+ BaseResult> result = new BaseResult<>(500, "SERVER EXCEPTION", null);
+ return new ResponseEntity<>(result, HttpStatus.OK);
+ }
+
+ @ResponseBody
+ @ExceptionHandler(RuntimeException.class)
+ public ResponseEntity> handleRuntimeException(RuntimeException e) {
+ log.error(">>> RuntimeException: {}", e.getLocalizedMessage());
+ StackTraceElement[] stackTraceElements = e.getStackTrace();
+ for (StackTraceElement stackTraceElement : stackTraceElements) {
+ if (stackTraceElement.getClassName().startsWith("com.alive") && stackTraceElement.getLineNumber() > 0) {
+ log.error("错误位置在:{}.{}(), {}行",
+ stackTraceElement.getClassName(),
+ stackTraceElement.getMethodName(),
+ stackTraceElement.getLineNumber());
+ }
+ }
+ String msg = e.getLocalizedMessage();
+ if (msg != null && msg.length() > 50) {
+ msg = msg.substring(0, 50);
+ }
+ BaseResult> result = new BaseResult<>(500, msg, null);
+ return new ResponseEntity<>(result, HttpStatus.OK);
+ }
+
+ @ResponseBody
+ @ExceptionHandler(IllegalArgumentException.class)
+ public ResponseEntity> handleException(IllegalArgumentException e) {
+ log.error(">>> IllegalArgumentException: {}", e.getLocalizedMessage());
+ // e.printStackTrace();
+ BaseResult> result = new BaseResult<>(400, e.getMessage(), null);
+ return new ResponseEntity<>(result, HttpStatus.OK);
+ }
+
+ @ResponseBody
+ @ExceptionHandler(HttpMessageNotReadableException.class)
+ public ResponseEntity> handleException(HttpMessageNotReadableException e) {
+ log.error(">>> HttpMessageNotReadableException: {}", e.getLocalizedMessage());
+ // e.printStackTrace();
+ BaseResult> result = new BaseResult<>(400, "Invalid Params", null);
+ return new ResponseEntity<>(result, HttpStatus.OK);
+ }
+
+ @ResponseBody
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity> handleException(MethodArgumentNotValidException e) {
+ log.error(">>> MethodArgumentNotValidException: {}", e.getLocalizedMessage());
+ //e.printStackTrace();
+ BaseResult> result = new BaseResult<>(400, e.getBindingResult().getAllErrors().get(0).getDefaultMessage(), null);
+ return new ResponseEntity<>(result, HttpStatus.OK);
+ }
+
+ @ResponseBody
+ @ExceptionHandler(DcException.class)
+ public ResponseEntity> handleException(DcException e) {
+ log.error(">>> DcException: {}", e.getLocalizedMessage());
+ //e.printStackTrace();
+
+ String message = MessageUtil.get(e.getResultCodeEnum().i18nKey());
+ BaseResult> result = new BaseResult<>(e.getCode(), message, null);
+ return new ResponseEntity<>(result, HttpStatus.OK);
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/model/AppPageReq.java b/alive-commons/src/main/java/com/alive/commons/model/AppPageReq.java
new file mode 100644
index 0000000..2e7617d
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/model/AppPageReq.java
@@ -0,0 +1,22 @@
+package com.alive.commons.model;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class AppPageReq {
+
+ @ApiModelProperty("上次最后一条数据的id,若没有传-1,默认-1")
+ private Integer last = -1;
+
+ @ApiModelProperty("分页大小,默认100,最大500")
+ private Integer size = 100;
+
+ public Integer getLast() {
+ return last == null || last == -1 ? Integer.MAX_VALUE : last;
+ }
+
+ public Integer getSize() {
+ return size == null || size > 500 ? 500 : size;
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/model/AppPageResp.java b/alive-commons/src/main/java/com/alive/commons/model/AppPageResp.java
new file mode 100644
index 0000000..3b9c43f
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/model/AppPageResp.java
@@ -0,0 +1,18 @@
+package com.alive.commons.model;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public abstract class AppPageResp {
+
+ @ApiModelProperty("最后1条数据的id,用于请求下1页数据,若为0,则是最后1页")
+ protected Integer last;
+
+ @ApiModelProperty("分页数据,空数组表示最后一页")
+ protected List list;
+
+ public abstract void fix();
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/model/BasePageReq.java b/alive-commons/src/main/java/com/alive/commons/model/BasePageReq.java
new file mode 100644
index 0000000..18828a3
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/model/BasePageReq.java
@@ -0,0 +1,53 @@
+package com.alive.commons.model;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class BasePageReq {
+
+ @ApiModelProperty("分页页码,从1开始")
+ private Integer page = 1;
+
+ @ApiModelProperty("分页大小,默认20,最大500")
+ private Integer size = 20;
+
+ //获取page对象,用于mybatis-plus,返回分页大小
+ @JsonIgnore
+ public IPage> getIPage() {
+ if (page == null) {
+ page = 1;
+ }
+ if (size == null) {
+ size = 20;
+ }
+ return new Page<>(page, size).setSearchCount(true);
+ }
+
+ @JsonIgnore
+ public IPage> getIPageForExport() {
+ return new Page<>(1, Integer.MAX_VALUE).setSearchCount(false);
+ }
+
+ //获取offset,用于手动处理sql
+ @JsonIgnore
+ public int getOffset() {
+ if (page == null) {
+ page = 1;
+ }
+ if (size == null) {
+ size = 20;
+ }
+ return page > 1 ? page * size - size : 0;
+ }
+
+ public int getSize() {
+ if (size == null || size <= 0 || size > 500) {
+ return 20;
+ }
+ return size;
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/model/BasePageResp.java b/alive-commons/src/main/java/com/alive/commons/model/BasePageResp.java
new file mode 100644
index 0000000..a4f349c
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/model/BasePageResp.java
@@ -0,0 +1,21 @@
+package com.alive.commons.model;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class BasePageResp {
+
+ private Integer total;
+
+ private List list;
+
+ public BasePageResp(Integer total, List list) {
+ this.total = total;
+ this.list = list;
+ }
+
+ public BasePageResp() {
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/model/BaseResult.java b/alive-commons/src/main/java/com/alive/commons/model/BaseResult.java
new file mode 100644
index 0000000..4c2fafd
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/model/BaseResult.java
@@ -0,0 +1,46 @@
+package com.alive.commons.model;
+
+import lombok.Data;
+
+@Data
+public class BaseResult {
+ private int code = 0;
+ private String msg = "Success";
+ private long timeMillis = System.currentTimeMillis();
+ private T data;
+
+ public BaseResult() {
+ }
+
+ public BaseResult(T data) {
+ this.data = data;
+ }
+
+ public BaseResult(int code, String msg) {
+ this.code = code;
+ this.msg = msg;
+ }
+
+ public BaseResult(int code, String msg, T data) {
+ this.code = code;
+ this.msg = msg;
+ this.data = data;
+ }
+
+ public static BaseResult> success(String msg) {
+ return new BaseResult<>(0, msg);
+ }
+
+ public static BaseResult> success() {
+ return new BaseResult<>(0, "Success");
+ }
+
+ public static BaseResult> error(String msg) {
+ return new BaseResult<>(400, msg);
+ }
+
+ public static BaseResult> error() {
+ return new BaseResult<>(400, "Failed");
+ }
+
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/model/BaseSummaryPageResp.java b/alive-commons/src/main/java/com/alive/commons/model/BaseSummaryPageResp.java
new file mode 100644
index 0000000..9519e0c
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/model/BaseSummaryPageResp.java
@@ -0,0 +1,18 @@
+package com.alive.commons.model;
+
+import lombok.Data;
+
+import java.util.Collections;
+
+@Data
+public class BaseSummaryPageResp extends BasePageResp {
+
+ private T summary;
+
+ public static BaseSummaryPageResp> emptyResult() {
+ BaseSummaryPageResp> resp = new BaseSummaryPageResp<>();
+ resp.setTotal(0);
+ resp.setList(Collections.emptyList());
+ return resp;
+ }
+}
\ No newline at end of file
diff --git a/alive-commons/src/main/java/com/alive/commons/model/EnumModel.java b/alive-commons/src/main/java/com/alive/commons/model/EnumModel.java
new file mode 100644
index 0000000..3e20f11
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/model/EnumModel.java
@@ -0,0 +1,19 @@
+package com.alive.commons.model;
+
+import lombok.Data;
+
+@Data
+public class EnumModel {
+
+ private String key;
+
+ private String label;
+
+ public EnumModel() {
+ }
+
+ public EnumModel(String key, String label) {
+ this.key = key;
+ this.label = label;
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/page/PageService.java b/alive-commons/src/main/java/com/alive/commons/page/PageService.java
new file mode 100644
index 0000000..10a2b6e
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/page/PageService.java
@@ -0,0 +1,43 @@
+package com.alive.commons.page;
+
+import com.alive.commons.model.BasePageReq;
+import com.alive.commons.model.BasePageResp;
+import com.alive.commons.util.RedisUtil;
+import com.alive.commons.util.Md5Util;
+import org.jooq.DSLContext;
+import org.jooq.SelectLimitStep;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author zcw
+ * @version 1.0.0
+ * @date 2018/06/19 16:44
+ * 分页工具
+ */
+@Service
+public class PageService {
+
+ @Autowired
+ private DSLContext dslContext;
+
+ @SuppressWarnings("unchecked")
+ public BasePageResp> getPageData(SelectLimitStep sql, BasePageReq pageReq, Class> responseType) {
+ String cacheKey = "PageServiceCount:" + Md5Util.md5(sql.getSQL(true).toLowerCase());
+ String cacheRes = RedisUtil.get(cacheKey);
+
+ int fetchCount = cacheRes == null ? dslContext.fetchCount(sql) : Integer.parseInt(cacheRes);
+ if (cacheRes == null && fetchCount > 10_0000) {
+ RedisUtil.setEx(cacheKey, fetchCount + "", 30);
+ }
+
+ if (fetchCount == 0) {
+ return new BasePageResp<>(0, Collections.emptyList());
+ }
+ List> list = sql.limit(pageReq.getOffset(), pageReq.getSize()).fetchInto(responseType);
+ return new BasePageResp<>(fetchCount, list);
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/redis/MyCacheKeyGenerator.java b/alive-commons/src/main/java/com/alive/commons/redis/MyCacheKeyGenerator.java
new file mode 100644
index 0000000..4f64e1e
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/redis/MyCacheKeyGenerator.java
@@ -0,0 +1,26 @@
+package com.alive.commons.redis;
+
+import com.alive.commons.util.Md5Util;
+import org.springframework.cache.interceptor.KeyGenerator;
+
+import java.lang.reflect.Method;
+
+/**
+ * 缓存key自定义生成规则,
+ */
+public class MyCacheKeyGenerator implements KeyGenerator {
+
+ @Override
+ public Object generate(Object target, Method method, Object... params) {
+ String className = target.getClass().getName();
+ String methodName = method.getName();
+ StringBuilder builder = new StringBuilder();
+
+ if (params.length > 0) {
+ for (int i = 0; i < params.length; i++) {
+ builder.append(params[i] != null ? params[i] : "NULL").append("&");
+ }
+ }
+ return String.format("%s:%s:%s", className, methodName, Md5Util.md5(builder.toString()));
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/redis/MyCacheManager.java b/alive-commons/src/main/java/com/alive/commons/redis/MyCacheManager.java
new file mode 100644
index 0000000..2e16ef6
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/redis/MyCacheManager.java
@@ -0,0 +1,32 @@
+package com.alive.commons.redis;
+
+import org.springframework.data.redis.cache.RedisCache;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+
+import java.time.Duration;
+
+/**
+ * 自定义缓存配置
+ */
+public class MyCacheManager extends RedisCacheManager {
+
+ //缓存key与过期时间分隔符
+ private static final String SEPARATOR = "#";
+
+ public MyCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
+ super(cacheWriter, defaultCacheConfiguration);
+ }
+
+ @Override
+ protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
+ String[] values = name.split(SEPARATOR);
+ if (values.length > 1) {
+ long second = Long.parseLong(values[1]);
+ cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(second));
+ }
+
+ return super.createRedisCache(name, cacheConfig);
+ }
+}
diff --git a/alive-commons/src/main/java/com/alive/commons/redis/RedisConfig.java b/alive-commons/src/main/java/com/alive/commons/redis/RedisConfig.java
new file mode 100644
index 0000000..c6824fd
--- /dev/null
+++ b/alive-commons/src/main/java/com/alive/commons/redis/RedisConfig.java
@@ -0,0 +1,41 @@
+package com.alive.commons.redis;
+
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.interceptor.KeyGenerator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+
+import java.time.Duration;
+
+@EnableCaching
+@Configuration
+public class RedisConfig {
+
+ //默认过期时间,10s
+ private static final int EXPIRATION_SECOND = 10;
+ public static final String KEY_GENERATOR_NAME = "MyKeyGenerator";
+ public static final String CACHE_KEY = "Cache";
+
+ @Bean
+ public MyCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
+ RedisSerializationContext.SerializationPair