xiatian 11 miesięcy temu
rodzic
commit
d8d8446513
17 zmienionych plików z 1502 dodań i 0 usunięć
  1. 117 0
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/OrgIpController.java
  2. 57 0
      examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ColumnSetting.java
  3. 48 0
      examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelError.java
  4. 31 0
      examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelProperty.java
  5. 163 0
      examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelReader.java
  6. 7 0
      examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelReaderHandle.java
  7. 70 0
      examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelUtils.java
  8. 186 0
      examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelWriter.java
  9. 38 0
      examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/util/ExportUtils.java
  10. 21 0
      examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/OrgIpRepo.java
  11. 100 0
      examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/entity/OrgIpEntity.java
  12. 28 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/OrgIpService.java
  13. 45 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/PagerQuery.java
  14. 85 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/orgip/OrgIpInfo.java
  15. 39 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/orgip/OrgIpQuery.java
  16. 51 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/orgip/OrgIpSave.java
  17. 416 0
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/OrgIpServiceImpl.java

+ 117 - 0
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/OrgIpController.java

@@ -0,0 +1,117 @@
+package cn.com.qmth.examcloud.core.examwork.api.controller;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import com.google.common.collect.Maps;
+
+import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
+import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.PathUtil;
+import cn.com.qmth.examcloud.core.examwork.base.util.ExportUtils;
+import cn.com.qmth.examcloud.core.examwork.service.OrgIpService;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpInfo;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpQuery;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpSave;
+import cn.com.qmth.examcloud.web.security.DataRule;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@Api(tags = "学习中心IP接口")
+@RequestMapping("${$rmp.ctr.examwork}/org/ip")
+public class OrgIpController extends ControllerSupport {
+
+	@Autowired
+	private OrgIpService orgIpService;
+
+	@DataRule(type = { DataRuleType.ORG })
+	@ApiOperation(value = "分页查询")
+	@PostMapping("page")
+	public PageInfo<OrgIpInfo> page(OrgIpQuery req) {
+		User user = getAccessUser();
+		req.setRootOrgId(user.getRootOrgId());
+		UserDataRule orgUd = getUserDataRule(DataRuleType.ORG);
+		req.setOrgUd(orgUd);
+		return orgIpService.getPage(req);
+	}
+
+	@ApiOperation(value = "新增")
+	@PostMapping("save")
+	public void add(OrgIpSave req) {
+		User user = getAccessUser();
+		req.setUser(user);
+		orgIpService.add(req);
+	}
+
+	@ApiOperation(value = "修改")
+	@PostMapping("update")
+	public void update(OrgIpSave req) {
+		User user = getAccessUser();
+		req.setUser(user);
+		orgIpService.update(req);
+	}
+
+	@ApiOperation(value = "删除")
+	@PostMapping("delete")
+	public void delete(List<Long> ids) {
+		User user = getAccessUser();
+		orgIpService.delete(ids, user.getRootOrgId());
+	}
+
+	@ApiOperation(value = "下载导入模板")
+	@GetMapping("template")
+	public void template(HttpServletResponse response) {
+		String resoucePath = PathUtil.getResoucePath("templates/orgIpImportTemplate.xlsx");
+		exportFile("IP登记导入模板.xlsx", new File(resoucePath));
+	}
+
+	@DataRule(type = { DataRuleType.ORG })
+	@ApiOperation(value = "导入IP")
+	@PostMapping("import")
+	public Map<String, Object> importIp(@RequestParam CommonsMultipartFile file) {
+		UserDataRule orgUd = getUserDataRule(DataRuleType.ORG);
+		if (orgUd.assertEmptyQueryResult()) {
+			throw new StatusException("学习中心权限为空");
+		}
+		List<String> failRecords = orgIpService.importIp(getAccessUser(), orgUd, file);
+		Map<String, Object> map = Maps.newHashMap();
+		map.put("hasError", CollectionUtils.isNotEmpty(failRecords));
+		map.put("failRecords", failRecords);
+		return map;
+	}
+
+	@DataRule(type = { DataRuleType.ORG })
+	@ApiOperation(value = "导出")
+	@PostMapping("export")
+	public void export(OrgIpQuery req,HttpServletResponse response) {
+		UserDataRule orgUd = getUserDataRule(DataRuleType.ORG);
+		List<OrgIpInfo> ret;
+		if (orgUd.assertEmptyQueryResult()) {
+			ret=new ArrayList<>();
+		}else {
+			User user = getAccessUser();
+			req.setRootOrgId(user.getRootOrgId());
+			req.setOrgUd(orgUd);
+			ret=orgIpService.listForExport(req);
+		}
+		ExportUtils.exportEXCEL("考点IP登记", OrgIpInfo.class, ret, response);
+	}
+}

+ 57 - 0
examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ColumnSetting.java

@@ -0,0 +1,57 @@
+package cn.com.qmth.examcloud.core.examwork.base.excel;
+
+public class ColumnSetting implements Comparable<ColumnSetting> {
+
+    private String header;
+    private String fieldName;
+    private int width;
+    private int index;
+
+    public ColumnSetting(String header,String fieldName, int width, int index) {
+        this.header = header;
+        this.fieldName = fieldName;
+        this.width = width;
+        this.index = index;
+    }
+
+    public String getHeader() {
+        return header;
+    }
+
+    public void setHeader(String header) {
+        this.header = header;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    public String getFieldName() {
+		return fieldName;
+	}
+
+	public void setFieldName(String fieldName) {
+		this.fieldName = fieldName;
+	}
+
+	@Override
+    public int compareTo(ColumnSetting columnSetting) {
+        if (index < columnSetting.getIndex())
+            return - 1 ;
+        if (index > columnSetting.getIndex())
+            return 1 ;
+        return 0 ;
+    }
+}

+ 48 - 0
examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelError.java

@@ -0,0 +1,48 @@
+package cn.com.qmth.examcloud.core.examwork.base.excel;
+/**
+ * 
+ * @Description: excel导入错误
+ * @author ting.yin
+ * @date 2016年8月19日
+ */
+public class ExcelError {
+
+	/**
+	 * 错误行数
+	 */
+	private int row;
+
+	/**
+	 * 错误类型
+	 */
+	private String excelErrorType;
+
+	public ExcelError() {
+
+	}
+
+	public ExcelError(int row, String excelErrorType) {
+		this.row = row;
+		this.excelErrorType = excelErrorType;
+	}
+	
+	public ExcelError(String excelErrorType) {
+		this.excelErrorType = excelErrorType;
+	}
+	public int getRow() {
+		return row;
+	}
+
+	public void setRow(int row) {
+		this.row = row;
+	}
+
+	public String getExcelErrorType() {
+		return excelErrorType;
+	}
+
+	public void setExcelErrorType(String excelErrorType) {
+		this.excelErrorType = excelErrorType;
+	}
+
+}

+ 31 - 0
examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelProperty.java

@@ -0,0 +1,31 @@
+package cn.com.qmth.examcloud.core.examwork.base.excel;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelProperty {
+	/**
+	 * 导出时列名
+	 */
+    String name() default "";
+    
+	/**
+	 * 导出时列宽
+	 */
+    int width() default 0;
+	/**
+	 * 排序
+	 */
+    int index();
+    /**
+     * 类型
+     * 0:导入(读excel)
+     * 1:导出(写excel)
+     * 2:导入&导出
+     */
+    int type() default 2;
+}

+ 163 - 0
examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelReader.java

@@ -0,0 +1,163 @@
+package cn.com.qmth.examcloud.core.examwork.base.excel;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import org.apache.commons.io.IOUtils;
+import org.apache.poi.ss.usermodel.*;
+
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 
+ * @Description: 读取excel
+ * @author ting.yin
+ * @date 2016年8月19日
+ */
+public class ExcelReader extends ExcelUtils {
+
+	private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+	public ExcelReader(Class<?> dataClass) {
+		super(dataClass, true);
+	}
+
+	/**
+	 * 
+	 * @param inputStream
+	 *            输入流
+	 * @param handle
+	 *            单个对象处理器
+	 * @return 错误信息集合
+	 */
+	public List<ExcelError> reader(InputStream inputStream, ExcelReaderHandle handle) {
+		List<ExcelError> excelErrors = new ArrayList<ExcelError>();
+		try {
+			Workbook wb = WorkbookFactory.create(inputStream);
+			Sheet sheet = wb.getSheetAt(0);
+			for (int i = 1; i <= sheet.getLastRowNum(); i++) {
+				Row row = sheet.getRow(i);
+				if (row == null) {
+					return excelErrors;
+				}
+				Object dto = getDataClass().newInstance();
+				for (int j = 0; j < this.getColumnSettings().size(); j++) {
+					ColumnSetting columnSetting = this.getColumnSettings().get(j);
+					Cell cell = row.getCell(columnSetting.getIndex());
+					Field field = getDataClass().getDeclaredField(columnSetting.getFieldName());
+					Object obj = convert(cell, field);
+					field.setAccessible(true);
+					field.set(dto, obj);
+				}
+				ExcelError error = handle.handle(dto);
+				if (error != null) {
+					error.setRow(i + 1);
+					excelErrors.add(error);
+				}
+			}
+		} catch (StatusException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new StatusException("580", "EXCEL导入失败", e);
+		} finally {
+			IOUtils.closeQuietly(inputStream);
+		}
+		return excelErrors;
+	}
+
+	private Object convert(Cell cell, Field field) {
+		if (cell != null) {
+			switch (cell.getCellType()) {
+				case Cell.CELL_TYPE_STRING :
+					return cell.getStringCellValue().toString();
+				case Cell.CELL_TYPE_BOOLEAN :
+					return String.valueOf(cell.getBooleanCellValue());
+				case Cell.CELL_TYPE_NUMERIC :
+					return processNumeric(cell, field);
+			}
+		}
+
+		return null;
+	}
+
+	private Object processNumeric(Cell cell, Field field) {
+
+		if (DateUtil.isCellDateFormatted(cell)) {
+
+			if (field.getType().isAssignableFrom(Date.class)) {
+				return cell.getDateCellValue();
+			} else {
+				return dateFormat.format(cell.getDateCellValue());
+			}
+
+		} else {
+
+			if (field.getType().isAssignableFrom(Integer.class)) {
+
+				return (int) cell.getNumericCellValue();
+
+			} else if (field.getType().isPrimitive() && field.getType().getName().equals("int")) {
+
+				return (int) cell.getNumericCellValue();
+
+			} else if (field.getType().isAssignableFrom(Long.class)) {
+
+				return (long) cell.getNumericCellValue();
+
+			} else if (field.getType().isPrimitive() && field.getType().getName().equals("long")) {
+
+				return (long) cell.getNumericCellValue();
+
+			} else if (field.getType().isAssignableFrom(Short.class)) {
+
+				return (short) cell.getNumericCellValue();
+
+			} else if (field.getType().isPrimitive() && field.getType().getName().equals("short")) {
+
+				return (short) cell.getNumericCellValue();
+
+			} else if (field.getType().isAssignableFrom(Float.class)) {
+
+				return (float) cell.getNumericCellValue();
+
+			} else if (field.getType().isPrimitive() && field.getType().getName().equals("float")) {
+
+				return (float) cell.getNumericCellValue();
+
+			} else if (field.getType().isAssignableFrom(Byte.class)) {
+
+				return (byte) cell.getNumericCellValue();
+
+			} else if (field.getType().isPrimitive() && field.getType().getName().equals("byte")) {
+
+				return (byte) cell.getNumericCellValue();
+
+			} else if (field.getType().isAssignableFrom(Double.class)) {
+
+				return cell.getNumericCellValue();
+
+			} else if (field.getType().isPrimitive()
+					&& field.getType().getName().equals("double")) {
+
+				return cell.getNumericCellValue();
+
+			} else if (field.getType().isAssignableFrom(String.class)) {
+
+				String numStr = String.valueOf(cell.getNumericCellValue());
+				if (numStr.contains("E")) {
+					numStr = new BigDecimal(numStr.trim()).toPlainString();
+				}
+				if (numStr.endsWith(".0"))
+					numStr = numStr.substring(0, numStr.indexOf(".0"));
+				return numStr;
+			} else {
+				return cell.getNumericCellValue();
+			}
+		}
+	}
+}

+ 7 - 0
examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelReaderHandle.java

@@ -0,0 +1,7 @@
+package cn.com.qmth.examcloud.core.examwork.base.excel;
+
+public interface ExcelReaderHandle {
+	
+	ExcelError handle(Object dto);
+
+}

+ 70 - 0
examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelUtils.java

@@ -0,0 +1,70 @@
+package cn.com.qmth.examcloud.core.examwork.base.excel;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2016/8/17.
+ */
+@SuppressWarnings("rawtypes")
+public abstract class ExcelUtils {
+
+	private Class dataClass;
+    private List<ColumnSetting> columnSettings;
+    
+    public ExcelUtils(Class<?> dataClass , boolean isRead){
+        this.dataClass = dataClass;
+        this.columnSettings = getColumnSettings(dataClass,isRead);
+    }
+
+    public Class getDataClass() {
+        return dataClass;
+    }
+
+    public void setDataClass(Class dataClass) {
+        this.dataClass = dataClass;
+    }
+
+    public List<ColumnSetting> getColumnSettings() {
+        return columnSettings;
+    }
+
+    public void setColumnSettings(List<ColumnSetting> columnSettings) {
+        this.columnSettings = columnSettings;
+    }
+
+    /**
+     * 提取ExcelProperty注解类的字段信息
+     * @param dataClass 需要解析excel的数据类型
+     * @return
+     */
+    protected List<ColumnSetting> getColumnSettings(Class<?> dataClass, boolean isRead){
+		List<ColumnSetting> columnSettings = new ArrayList<>();
+		Field[] fileds = dataClass.getDeclaredFields();
+		for (Field field : fileds) {
+			ExcelProperty exportProperty = field.getAnnotation(ExcelProperty.class);
+			if (exportProperty != null) {
+				if (isRead) {
+					if (exportProperty.type() == 0 || exportProperty.type() == 2) {
+						ColumnSetting columnSetting = new ColumnSetting(
+								exportProperty.name(),field.getName(),exportProperty.width(),
+								exportProperty.index());
+						columnSettings.add(columnSetting);
+					}
+				}else{
+					if (exportProperty.type() == 1 || exportProperty.type() == 2) {
+						ColumnSetting columnSetting = new ColumnSetting(
+								exportProperty.name(), field.getName(),exportProperty.width(),
+								exportProperty.index());
+						columnSettings.add(columnSetting);
+					}
+				}
+			}
+		}
+		Collections.sort(columnSettings);
+		return columnSettings;
+    }
+    
+}

+ 186 - 0
examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/excel/ExcelWriter.java

@@ -0,0 +1,186 @@
+package cn.com.qmth.examcloud.core.examwork.base.excel;
+
+import org.apache.poi.xssf.usermodel.*;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by dizhi on 2016/6/19.
+ */
+public class ExcelWriter extends ExcelUtils {
+
+
+    public ExcelWriter(Class<?> dataClass) {
+        super(dataClass, false);
+    }
+
+    /**
+     * 写入excel
+     *
+     * @param sheetName sheet名称
+     * @param dataset   数据集合
+     * @param out       输出流
+     */
+    public void write(String sheetName, Collection<?> dataset, OutputStream out) {
+        // 声明一个工作薄
+        XSSFWorkbook workbook = new XSSFWorkbook();
+        // 生成一个表格
+        XSSFSheet sheet = workbook.createSheet(sheetName);
+
+        // 设置表格默认列宽度为15个字节
+        sheet.setDefaultColumnWidth((short) 15);
+        // 生成一个样式
+        XSSFCellStyle style = workbook.createCellStyle();
+        // 设置这些样式
+//        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
+//        style.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
+//        style.setBorderBottom(XSSFCellStyle.BORDER_THIN);
+//        style.setBorderLeft(XSSFCellStyle.BORDER_THIN);
+//        style.setBorderRight(XSSFCellStyle.BORDER_THIN);
+//        style.setBorderTop(XSSFCellStyle.BORDER_THIN);
+//        style.setAlignment(XSSFCellStyle.ALIGN_CENTER);
+        // 生成一个字体
+//        XSSFFont font = workbook.createFont();
+//        font.setColor(HSSFColor.VIOLET.index);
+//        font.setFontHeightInPoints((short) 12);
+//        font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
+//        // 把字体应用到当前的样式
+//        style.setFont(font);
+//        // 生成并设置另一个样式
+//        XSSFCellStyle style2 = workbook.createCellStyle();
+//        style2.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);
+//        style2.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
+//        style2.setBorderBottom(XSSFCellStyle.BORDER_THIN);
+//        style2.setBorderLeft(XSSFCellStyle.BORDER_THIN);
+//        style2.setBorderRight(XSSFCellStyle.BORDER_THIN);
+//        style2.setBorderTop(XSSFCellStyle.BORDER_THIN);
+//        style2.setAlignment(XSSFCellStyle.ALIGN_CENTER);
+//        style2.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
+//        // 生成另一个字体
+//        XSSFFont font2 = workbook.createFont();
+//        font2.setBoldweight(XSSFFont.BOLDWEIGHT_NORMAL);
+        // 把字体应用到当前的样式
+        //style2.setFont(font2);
+
+        // 声明一个画图的顶级管理器
+        //HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
+        // 定义注释的大小和位置,详见文档
+//        XSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0,
+//                0, 0, 0, (short) 4, 2, (short) 6, 5));
+//        // 设置注释内容
+//        comment.setString(new HSSFRichTextString("可以在POI中添加注释!"));
+//        // 设置注释作者,当鼠标移动到单元格上是可以在状态栏中看到该内容.
+//        comment.setAuthor("leno");
+
+        List<ColumnSetting> columnSettings = this.getColumnSettings();
+
+        // 产生表格标题行
+        XSSFRow row = sheet.createRow(0);
+        for (short i = 0; i < columnSettings.size(); i++) {
+            XSSFCell cell = row.createCell(i);
+            cell.setCellStyle(style);
+            XSSFRichTextString text = new XSSFRichTextString(columnSettings.get(i).getHeader());
+            cell.setCellValue(text);
+            if (columnSettings.get(i).getWidth() > 0) {
+                sheet.setColumnWidth(i, columnSettings.get(i).getWidth() * 256);
+            }
+        }
+
+        // 遍历集合数据,产生数据行
+        //Iterator<?> it = dataset.iterator();
+        int index = 0;
+        for (Object obj : dataset) {
+            index++;
+            row = sheet.createRow(index);
+            //T t = (T) it.next();
+            // 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
+            for (short i = 0; i < columnSettings.size(); i++) {
+                XSSFCell cell = row.createCell(i);
+                //cell.setCellStyle(style2);
+                String fieldName = columnSettings.get(i).getFieldName();
+
+                try {
+                    Field field = this.getDataClass().getDeclaredField(fieldName);
+                    field.setAccessible(true);
+                    Object value = field.get(obj);
+                    // 判断值的类型后进行强制类型转换
+                    String textValue = null;
+                    // if (value instanceof Integer) {
+                    // int intValue = (Integer) value;
+                    // cell.setCellValue(intValue);
+                    // } else if (value instanceof Float) {
+                    // float fValue = (Float) value;
+                    // textValue = new HSSFRichTextString(
+                    // String.valueOf(fValue));
+                    // cell.setCellValue(textValue);
+                    // } else if (value instanceof Double) {
+                    // double dValue = (Double) value;
+                    // textValue = new HSSFRichTextString(
+                    // String.valueOf(dValue));
+                    // cell.setCellValue(textValue);
+                    // } else if (value instanceof Long) {
+                    // long longValue = (Long) value;
+                    // cell.setCellValue(longValue);
+                    // }
+                    if (value == null) {
+                        textValue = "";
+                    } else if (value instanceof Boolean) {
+                        boolean bValue = (Boolean) value;
+                        textValue = "是";
+                        if (!bValue) {
+                            textValue = "否";
+                        }
+                    } else if (value instanceof Date) {
+                        Date date = (Date) value;
+                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+                        textValue = sdf.format(date);
+                    } else {
+                        // 其它数据类型都当作字符串简单处理
+                        textValue = String.valueOf(value);
+                    }
+                    // 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成
+                    if (textValue != null) {
+                        Pattern p = Pattern.compile("^//d+(//.//d+)?$");
+                        Matcher matcher = p.matcher(textValue);
+                        if (matcher.matches()) {
+                            // 是数字当作double处理
+                            cell.setCellValue(Double.parseDouble(textValue));
+                        } else {
+                            XSSFRichTextString richString = new XSSFRichTextString(
+                                    textValue);
+
+                            cell.setCellValue(richString);
+                        }
+                    } else {
+                        textValue = "";
+                    }
+                } catch (NoSuchFieldException e) {
+                    e.printStackTrace();
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                } catch (SecurityException e) {
+                    e.printStackTrace();
+                } catch (IllegalArgumentException e) {
+                    e.printStackTrace();
+                } finally {
+                    // 清理资源
+                }
+            }
+
+        }
+        try {
+            workbook.write(out);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+    }
+}

+ 38 - 0
examcloud-core-examwork-base/src/main/java/cn/com/qmth/examcloud/core/examwork/base/util/ExportUtils.java

@@ -0,0 +1,38 @@
+package cn.com.qmth.examcloud.core.examwork.base.util;
+
+import java.net.URLEncoder;
+import java.util.Collection;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+
+import cn.com.qmth.examcloud.core.examwork.base.excel.ExcelWriter;
+
+
+
+/*
+ * excel导出工具
+ */
+public class ExportUtils {
+
+    private static final String DEFALUT_CONTENT_TYPE = "application/vnd.ms-excel";
+
+    private static final String DEFALUT_EXT = ".xlsx";
+
+    public static void exportEXCEL(String fileName,Class<?> dataClass,
+                             Collection<?> dataset,HttpServletResponse response) {
+        try {
+        	
+            response.setHeader("Content-Disposition", "inline; filename="
+                    +URLEncoder.encode(fileName, "UTF-8") + DEFALUT_EXT);
+            response.setContentType(DEFALUT_CONTENT_TYPE);
+            ServletOutputStream outputStream = response.getOutputStream();
+            ExcelWriter excelExporter = new ExcelWriter(dataClass);
+            excelExporter.write("sheet1",dataset,outputStream);
+            outputStream.flush();
+            outputStream.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 21 - 0
examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/OrgIpRepo.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.examcloud.core.examwork.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.QueryByExampleExecutor;
+
+import cn.com.qmth.examcloud.core.examwork.dao.entity.OrgIpEntity;
+
+public interface OrgIpRepo extends JpaRepository<OrgIpEntity, Long>,
+			QueryByExampleExecutor<OrgIpEntity>, JpaSpecificationExecutor<OrgIpEntity> {
+
+	OrgIpEntity findByRootOrgIdAndOrgIdAndIp(Long rootOrgId, Long orgId, String ip);
+
+    @Modifying
+    @Query(value = "delete from ec_e_org_ip  where id in ?1 and root_org_id = ?2 ",nativeQuery = true)
+    int delete(List<Long> ids, Long rootOrgId);
+}

+ 100 - 0
examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/entity/OrgIpEntity.java

@@ -0,0 +1,100 @@
+package cn.com.qmth.examcloud.core.examwork.dao.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Index;
+import javax.persistence.Table;
+
+import cn.com.qmth.examcloud.web.jpa.JpaEntity;
+
+@Entity
+@Table(name = "ec_e_org_ip", indexes = { @Index(name = "IDX_E_ORG_IP_01", columnList = "rootOrgId,orgId")})
+public class OrgIpEntity extends JpaEntity {
+
+	private static final long serialVersionUID = -7956507246258115392L;
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	private Long id;
+
+	@Column(nullable = false)
+	private Long rootOrgId;
+
+	@Column(nullable = false)
+	private Long orgId;
+
+	/**
+	 * ip地址
+	 */
+	@Column(nullable = false)
+	private String ip;
+	@Column(nullable = false)
+	private Long creationBy;
+	@Column(nullable = false)
+	private Long updateBy;
+	/**
+	 * ip地址归属的学习中心备注信息
+	 */
+	@Column(length = 100)
+	private String remark;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public String getIp() {
+		return ip;
+	}
+
+	public void setIp(String ip) {
+		this.ip = ip;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public Long getCreationBy() {
+		return creationBy;
+	}
+
+	public void setCreationBy(Long creationBy) {
+		this.creationBy = creationBy;
+	}
+
+	public Long getUpdateBy() {
+		return updateBy;
+	}
+
+	public void setUpdateBy(Long updateBy) {
+		this.updateBy = updateBy;
+	}
+
+}

+ 28 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/OrgIpService.java

@@ -0,0 +1,28 @@
+package cn.com.qmth.examcloud.core.examwork.service;
+
+import java.util.List;
+
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpInfo;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpQuery;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpSave;
+
+public interface OrgIpService {
+
+	PageInfo<OrgIpInfo> getPage(OrgIpQuery req);
+
+	void add(OrgIpSave req);
+
+	void update(OrgIpSave req);
+
+	void delete(List<Long> ids, Long rootOrgId);
+
+	List<String> importIp(User user, UserDataRule orgUd, CommonsMultipartFile file);
+
+	List<OrgIpInfo> listForExport(OrgIpQuery req);
+
+}

+ 45 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/PagerQuery.java

@@ -0,0 +1,45 @@
+/*
+ * *************************************************
+ * Copyright (c) 2019 QMTH. All Rights Reserved. Created by Deason on 2019-09-24
+ * 14:10:50. *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.examwork.service.bean;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class PagerQuery {
+
+    @ApiModelProperty(value = "第几页(从1开始)")
+    protected Integer pageNumber;
+
+    @ApiModelProperty(value = "每页条数")
+    protected Integer pageSize;
+
+    public Integer getPageNumber() {
+        // 默认值
+        if (pageNumber == null || pageNumber < 1) {
+        	pageNumber = 1;
+        }
+
+        return pageNumber;
+    }
+
+    public Integer getPageSize() {
+        // 默认值
+        if (pageSize == null || pageSize < 1) {
+            pageSize = 10;
+        }
+
+        return pageSize;
+    }
+
+    public void setPageNumber(Integer pageNumber) {
+        this.pageNumber = pageNumber;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+}

+ 85 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/orgip/OrgIpInfo.java

@@ -0,0 +1,85 @@
+package cn.com.qmth.examcloud.core.examwork.service.bean.orgip;
+
+import java.util.Date;
+
+import cn.com.qmth.examcloud.core.examwork.base.excel.ExcelProperty;
+
+public class OrgIpInfo {
+	private Long id;
+	private Long orgId;
+	@ExcelProperty(index = 2,name = "学习中心名称")
+	private String orgName;
+	@ExcelProperty(index = 1,name = "学校中心代码")
+	private String orgCode;
+	@ExcelProperty(index = 0,name = "IP/IP段")
+	private String ip;
+	@ExcelProperty(index = 3,name = "备注")
+	private String remark;
+	private Date updateTime;
+	private String updateName;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public String getOrgName() {
+		return orgName;
+	}
+
+	public void setOrgName(String orgName) {
+		this.orgName = orgName;
+	}
+
+	public String getOrgCode() {
+		return orgCode;
+	}
+
+	public void setOrgCode(String orgCode) {
+		this.orgCode = orgCode;
+	}
+
+	public String getIp() {
+		return ip;
+	}
+
+	public void setIp(String ip) {
+		this.ip = ip;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public Date getUpdateTime() {
+		return updateTime;
+	}
+
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	public String getUpdateName() {
+		return updateName;
+	}
+
+	public void setUpdateName(String updateName) {
+		this.updateName = updateName;
+	}
+
+}

+ 39 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/orgip/OrgIpQuery.java

@@ -0,0 +1,39 @@
+package cn.com.qmth.examcloud.core.examwork.service.bean.orgip;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
+import cn.com.qmth.examcloud.core.examwork.service.bean.PagerQuery;
+import io.swagger.annotations.ApiModelProperty;
+
+public class OrgIpQuery extends PagerQuery {
+	@ApiModelProperty(hidden = true)
+	private Long rootOrgId;
+	@ApiModelProperty("学习中心ID")
+	private Long orgId;
+	@ApiModelProperty(hidden = true)
+	private UserDataRule orgUd;
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public UserDataRule getOrgUd() {
+		return orgUd;
+	}
+
+	public void setOrgUd(UserDataRule orgUd) {
+		this.orgUd = orgUd;
+	}
+
+}

+ 51 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/bean/orgip/OrgIpSave.java

@@ -0,0 +1,51 @@
+package cn.com.qmth.examcloud.core.examwork.service.bean.orgip;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import io.swagger.annotations.ApiModelProperty;
+
+public class OrgIpSave  {
+	@ApiModelProperty("ID")
+	private Long id;
+	@ApiModelProperty(hidden = true)
+	private User user;
+	@ApiModelProperty("学习中心ID")
+	private Long orgId;
+	@ApiModelProperty("ip")
+	private String ip;
+	@ApiModelProperty("备注")
+	private String remark;
+	
+	
+	public User getUser() {
+		return user;
+	}
+	public void setUser(User user) {
+		this.user = user;
+	}
+	public Long getOrgId() {
+		return orgId;
+	}
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+	public String getIp() {
+		return ip;
+	}
+	public void setIp(String ip) {
+		this.ip = ip;
+	}
+	public String getRemark() {
+		return remark;
+	}
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+}

+ 416 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/OrgIpServiceImpl.java

@@ -0,0 +1,416 @@
+package cn.com.qmth.examcloud.core.examwork.service.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.criteria.Predicate;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.helpers.poi.ExcelReader;
+import cn.com.qmth.examcloud.core.basic.api.OrgCloudService;
+import cn.com.qmth.examcloud.core.basic.api.UserCloudService;
+import cn.com.qmth.examcloud.core.basic.api.request.GetOrgReq;
+import cn.com.qmth.examcloud.core.basic.api.request.GetUserReq;
+import cn.com.qmth.examcloud.core.basic.api.response.GetOrgResp;
+import cn.com.qmth.examcloud.core.basic.api.response.GetUserResp;
+import cn.com.qmth.examcloud.core.examwork.dao.OrgIpRepo;
+import cn.com.qmth.examcloud.core.examwork.dao.entity.OrgIpEntity;
+import cn.com.qmth.examcloud.core.examwork.service.OrgIpService;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpInfo;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpQuery;
+import cn.com.qmth.examcloud.core.examwork.service.bean.orgip.OrgIpSave;
+import cn.com.qmth.examcloud.support.cache.CacheHelper;
+import cn.com.qmth.examcloud.support.cache.bean.OrgCacheBean;
+import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
+import cn.com.qmth.examcloud.web.jpa.PageUtils;
+
+@Service
+public class OrgIpServiceImpl implements OrgIpService {
+    private static final Logger log = LoggerFactory.getLogger(OrgIpService.class);
+	private static final String[] EXCEL_HEADER = new String[] { "IP/IP段", "学习中心代码", "学习中心名称", "备注" };
+	@Autowired
+	private OrgIpRepo orgIpRepo;
+
+	@Autowired
+	private UserCloudService userCloudService;
+
+	@Autowired
+	private OrgCloudService orgCloudService;
+
+	@Override
+	public PageInfo<OrgIpInfo> getPage(OrgIpQuery req) {
+		if (req.getOrgUd().assertEmptyQueryResult()) {
+			return PageUtils.toPageInfo(Page.empty());
+		}
+		Specification<OrgIpEntity> specification = (root, query, cb) -> {
+			List<Predicate> predicates = new ArrayList<>();
+			predicates.add(cb.equal(root.get("rootOrgId"), req.getRootOrgId()));
+
+			if (req.getOrgUd().assertNeedQueryRefIds()) {
+				predicates.add(root.get("orgId").in(req.getOrgUd().getRefIds()));
+			}
+
+			if (req.getOrgId() != null) {
+				predicates.add(cb.equal(root.get("orgId"), req.getOrgId()));
+			}
+
+			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+		};
+
+		PageRequest pageRequest = PageRequest.of(req.getPageNumber(), req.getPageSize(),
+				Sort.by(Direction.DESC, "updateTime"));
+
+		Page<OrgIpEntity> page = orgIpRepo.findAll(specification, pageRequest);
+		if (CollectionUtils.isEmpty(page.getContent())) {
+			return PageUtils.toPageInfo(Page.empty());
+		}
+		List<OrgIpInfo> ret = new ArrayList<>();
+		for (OrgIpEntity e : page.getContent()) {
+			OrgIpInfo info = new OrgIpInfo();
+			ret.add(info);
+			info.setId(e.getId());
+			info.setIp(e.getIp());
+			info.setOrgId(e.getOrgId());
+			OrgCacheBean org = CacheHelper.getOrg(e.getOrgId());
+			info.setOrgCode(org.getCode());
+			info.setOrgName(org.getName());
+			GetUserReq uq = new GetUserReq();
+			uq.setRootOrgId(req.getRootOrgId());
+			uq.setUserId(e.getUpdateBy());
+			GetUserResp res = userCloudService.getUser(uq);
+			info.setRemark(e.getRemark());
+			info.setUpdateTime(e.getUpdateTime());
+			info.setUpdateName(res.getUserBean().getName() + "(" + res.getUserBean().getLoginName() + ")");
+		}
+		return PageUtils.toPageInfo(page, ret);
+	}
+
+	@Transactional
+	@Override
+	public void add(OrgIpSave req) {
+		if (req.getOrgId() == null) {
+			throw new StatusException("学习中心不能为空");
+		}
+		checkIp(req.getIp());
+		req.setIp(req.getIp().trim());
+		if (req.getRemark() != null && req.getRemark().length() > 200) {
+			throw new StatusException("备注长度不能超过200");
+		}
+		checkIpExists(req);
+		OrgIpEntity e = new OrgIpEntity();
+		e.setCreationBy(req.getUser().getUserId());
+		e.setUpdateBy(req.getUser().getUserId());
+		e.setIp(req.getIp());
+		e.setRemark(req.getRemark());
+		e.setRootOrgId(req.getUser().getRootOrgId());
+		orgIpRepo.save(e);
+	}
+
+	@Transactional
+	@Override
+	public void update(OrgIpSave req) {
+		if (req.getId() == null) {
+			throw new StatusException("id不能为空");
+		}
+		if (req.getOrgId() == null) {
+			throw new StatusException("学习中心不能为空");
+		}
+		checkIp(req.getIp());
+		req.setIp(req.getIp().trim());
+		if (req.getRemark() != null && req.getRemark().length() > 200) {
+			throw new StatusException("备注长度不能超过200");
+		}
+		checkIpExists(req);
+		OrgIpEntity e = GlobalHelper.getPresentEntity(orgIpRepo, req.getId(), OrgIpEntity.class);
+		e.setUpdateBy(req.getUser().getUserId());
+		e.setIp(req.getIp());
+		e.setRemark(req.getRemark());
+		orgIpRepo.save(e);
+	}
+
+	private void checkIpExists(OrgIpSave req) {
+		OrgIpEntity oi = orgIpRepo.findByRootOrgIdAndOrgIdAndIp(req.getUser().getRootOrgId(), req.getOrgId(),
+				req.getIp());
+		if (req.getId() == null && oi != null) {
+			OrgCacheBean org = CacheHelper.getOrg(req.getOrgId());
+			throw new StatusException("学习中心[" + org.getCode() + "] ip[" + req.getIp() + "]已存在");
+		}
+		if (req.getId() != null && oi != null && !oi.getId().equals(req.getId())) {
+			OrgCacheBean org = CacheHelper.getOrg(req.getOrgId());
+			throw new StatusException("学习中心[" + org.getCode() + "] ip[" + req.getIp() + "]已存在");
+		}
+	}
+
+	private void checkIp(String ip) {
+		if (StringUtils.isBlank(ip)) {
+			throw new StatusException("ip不能为空");
+		}
+		String[] ss1 = ip.split("\\.");
+		if (ss1.length != 4) {
+			throw new StatusException("ip格式错误");
+		}
+		for (String s : ss1) {
+			if (s.indexOf("-") != -1) {
+				String[] ss2 = ip.split("-");
+				if (ss2.length != 2) {
+					throw new StatusException("ip段格式错误");
+				}
+				for (String s2 : ss2) {
+					checkIpNumber(s2);
+				}
+				if (Integer.valueOf(ss2[0]) >= Integer.valueOf(ss2[1])) {
+					throw new StatusException("ip段格式错误,起始数值必须小于截止数值");
+				}
+			} else {
+				checkIpNumber(s);
+			}
+		}
+	}
+
+	private void checkIpNumber(String s) {
+		try {
+			int val = Integer.valueOf(s);
+			if (val < 0 || val > 255) {
+				throw new StatusException("ip数值只能是0~255");
+			}
+		} catch (NumberFormatException e) {
+			throw new StatusException("ip只能是整数");
+		}
+	}
+
+	@Transactional
+	@Override
+	public void delete(List<Long> ids, Long rootOrgId) {
+		orgIpRepo.delete(ids, rootOrgId);
+	}
+
+    private String newError(int lineNum, String msg) {
+        return "第"+lineNum+"行 "+msg;
+    }
+
+	private String trimAndNullIfBlank(String s) {
+		if (StringUtils.isBlank(s)) {
+			return null;
+		}
+		return s.trim();
+	}
+
+	private boolean headerError(String[] header) {
+		for (int i = 0; i < EXCEL_HEADER.length; i++) {
+			if (null == header[i]) {
+				return true;
+			}
+			if (!EXCEL_HEADER[i].equals(header[i].trim())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	@Transactional
+	@Override
+	public List<String> importIp(User user, UserDataRule orgUd, CommonsMultipartFile file) {
+		List<String[]> lineList = null;
+		try {
+			lineList = ExcelReader.readSheetBySax(file.getInputStream(), 1, 4);
+		} catch (Exception e) {
+			throw new StatusException("Excel 解析失败");
+		}
+
+		if (CollectionUtils.isEmpty(lineList)) {
+			throw new StatusException("Excel无内容");
+		}
+
+		if (10001 < lineList.size()) {
+			throw new StatusException("数据行数不能超过10000");
+		}
+
+		List<String> failRecords = new ArrayList<>();
+
+		List<OrgIpSave> list = new ArrayList<>();
+		Map<String, Long> orgMap = new HashMap<>();
+		for (int i = 0; i < lineList.size(); i++) {
+			String[] line = lineList.get(i);
+			if (0 == i) {
+				if (headerError(line)) {
+					throw new StatusException("Excel表头错误");
+				}
+				continue;
+			}
+
+			boolean hasError = false;
+			StringBuilder msg = new StringBuilder();
+
+			OrgIpSave info = new OrgIpSave();
+			info.setUser(user);
+
+			String ip = trimAndNullIfBlank(line[0]);
+			if (StringUtils.isBlank(ip)) {
+				msg.append("  IP/IP段不能为空");
+				hasError = true;
+			} else if (ip.length() > 100) {
+				msg.append("  IP/IP段不能超过100个字符");
+				hasError = true;
+			} else {
+				try {
+					checkIp(ip);
+				} catch (StatusException e) {
+					msg.append("  " + e.getDesc());
+					hasError = true;
+				}
+			}
+			info.setIp(ip);
+
+			String code = trimAndNullIfBlank(line[1]);
+			if (StringUtils.isBlank(code)) {
+				msg.append("  学习中心代码不能为空");
+				hasError = true;
+			} else {
+				try {
+					Long orgId = getOrgId(orgMap, user.getRootOrgId(), code, orgUd);
+					info.setOrgId(orgId);
+				} catch (StatusException e) {
+					msg.append("  " + e.getDesc());
+					hasError = true;
+				}
+
+			}
+
+			String remark = trimAndNullIfBlank(line[3]);
+			if (remark != null && remark.length() > 200) {
+				msg.append("  备注长度不能超过200");
+				hasError = true;
+			}
+			info.setRemark(remark);
+
+			if (hasError) {
+				failRecords.add(newError(i + 2, msg.toString()));
+			} else {
+				list.add(info);
+			}
+
+		}
+
+		if (CollectionUtils.isNotEmpty(failRecords)) {
+			return failRecords;
+		}
+
+		int i = 1;
+		for (OrgIpSave cur : list) {
+			try {
+				saveForImport(cur);
+			} catch (StatusException e) {
+				failRecords.add(newError(i + 1, e.getDesc()));
+			} catch (Exception e) {
+                failRecords.add(newError(i + 1, "系统异常"));
+                log.error("IP导入系统异常", e);
+            }
+		}
+        if (CollectionUtils.isNotEmpty(failRecords)) {
+            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+        }
+		return failRecords;
+	}
+
+	private void saveForImport(OrgIpSave req) {
+		if (req.getOrgId() == null) {
+			throw new StatusException("学习中心不能为空");
+		}
+		req.setIp(req.getIp().trim());
+		if (req.getRemark() != null && req.getRemark().length() > 200) {
+			throw new StatusException("备注长度不能超过200");
+		}
+		try {
+			checkIpExists(req);
+		} catch (StatusException e) {
+			return;
+		}
+		OrgIpEntity e = new OrgIpEntity();
+		e.setCreationBy(req.getUser().getUserId());
+		e.setUpdateBy(req.getUser().getUserId());
+		e.setIp(req.getIp());
+		e.setRemark(req.getRemark());
+		e.setRootOrgId(req.getUser().getRootOrgId());
+		orgIpRepo.save(e);
+	}
+
+	private Long getOrgId(Map<String, Long> orgMap, Long rootOrgId, String orgCode, UserDataRule orgUd) {
+		Long id = orgMap.get(orgCode);
+		if (id != null) {
+			return id;
+		}
+		GetOrgReq req = new GetOrgReq();
+		req.setRootOrgId(rootOrgId);
+		req.setOrgCode(orgCode);
+		GetOrgResp res = orgCloudService.getOrg(req);
+		if (res == null || res.getOrg() == null) {
+			throw new StatusException("未找到学习中心信息");
+		}
+		if (orgUd.assertNeedQueryRefIds() && !orgUd.getRefIds().contains(res.getOrg().getId())) {
+			throw new StatusException("没有该学习中心权限");
+		}
+		id = res.getOrg().getId();
+		orgMap.put(orgCode, id);
+		return id;
+	}
+
+	@Override
+	public List<OrgIpInfo> listForExport(OrgIpQuery req) {
+		if (req.getOrgUd().assertEmptyQueryResult()) {
+			return new ArrayList<>();
+		}
+		Specification<OrgIpEntity> specification = (root, query, cb) -> {
+			List<Predicate> predicates = new ArrayList<>();
+			predicates.add(cb.equal(root.get("rootOrgId"), req.getRootOrgId()));
+
+			if (req.getOrgUd().assertNeedQueryRefIds()) {
+				predicates.add(root.get("orgId").in(req.getOrgUd().getRefIds()));
+			}
+
+			if (req.getOrgId() != null) {
+				predicates.add(cb.equal(root.get("orgId"), req.getOrgId()));
+			}
+
+			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+		};
+
+		List<OrgIpEntity> list = orgIpRepo.findAll(specification, Sort.by(Direction.DESC, "updateTime"));
+		if (CollectionUtils.isEmpty(list)) {
+			return new ArrayList<>();
+		}
+		List<OrgIpInfo> ret = new ArrayList<>();
+		for (OrgIpEntity e : list) {
+			OrgIpInfo info = new OrgIpInfo();
+			ret.add(info);
+			info.setId(e.getId());
+			info.setIp(e.getIp());
+			info.setOrgId(e.getOrgId());
+			OrgCacheBean org = CacheHelper.getOrg(e.getOrgId());
+			info.setOrgCode(org.getCode());
+			info.setOrgName(org.getName());
+			info.setRemark(e.getRemark());
+			info.setUpdateTime(e.getUpdateTime());
+		}
+		return ret;
+	}
+}