利用freemarker对参数进行校验
这篇文章主要用到的技术点:

自定义注解的使用
反射机制
SAX解析xml
Freemarker的运用
我们在工作中经常需要上传excel文件,然后在对文件中的字段进行校验。如果文件里的字段是反复出现,或者文件的字段比较多的话,这是就会使代码变得繁琐,而且也不容易维护。
比如说像下面那张学生的表格

我们需要对上面表中的每个字段做校验
1.userName 必传字段
2. telephone 手机电话号码格式校验
3. email格式的校验
4. birthday 格式的校验
5. userId的生成规则等

有时候我们用自定义注解+反射,往往可以使代码变得清晰明了,不说了,直接上代码:

package com.example.demo.Controller;

import com.example.demo.utils.DealException;
import com.example.demo.utils.ExcelUtils;
import com.example.demo.validate.TemplateXmlUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS;

@RestController
public class UploadExcelController {
@RequestMapping("/upload")
public Object uploadFile(MultipartFile file) throws IOException, TemplateException {
//读取文件的基本信息
String filename = file.getOriginalFilename();
InputStream inputStream = file.getInputStream();
try {
// Workbook workbook = ExcelUtils.buildWorkookFromStream(filename, inputStream);
//解析excel
List<Map<String, Object>> maps = ExcelUtils.excelToList(filename, inputStream, 0, 0);
Configuration configuration = new Configuration(DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
URL url = this.getClass().getClassLoader().getResource("freemarkers");
configuration.setDirectoryForTemplateLoading(new File(url.getFile()));
Template template = configuration.getTemplate("userMapper.ftl");
HashMap<String, Object> objMap = new HashMap<>();
objMap.put("maps",maps);
StringWriter sw = new StringWriter();
template.process(objMap,sw);
System.out.println(sw.toString());

String s = TemplateXmlUtil.analysisXml(sw.toString(), "UTF-8");
System.out.println(s);
return s;

} catch (DealException e) {
e.printStackTrace();
}
return null;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
这段代码首先解析了excel文件,将文件转化成list,下面贴出excelutils的代码

package com.example.demo.utils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExcelUtils {
public static Workbook buildWorkookFromStream(String excelFileName, InputStream excelStream) throws IOException, DealException {
Workbook book=null;
if (excelFileName.endsWith("xls")){
book = new HSSFWorkbook(excelStream);
}else if(excelFileName.endsWith("xlsx")){
book=new XSSFWorkbook(excelStream);
}else{
throw new DealException("000000","文件初始化失败");
}
return book;
}

public static List<Map<String,Object>> excelToList(String excelName, InputStream excelStream, Integer sheetIndex, Integer startRow) throws IOException, DealException {
List<Map<String,Object>> resultList=new ArrayList<>();
Workbook workbook = buildWorkookFromStream(excelName, excelStream);
Sheet sheet = workbook.getSheetAt(sheetIndex);
//获取第一行的抬头
Row row = sheet.getRow(startRow);
int cellsNum = row.getPhysicalNumberOfCells();
List<String> titleList = new ArrayList<>();
for (int i = 0; i <cellsNum ; i++) {
Cell cell = row.getCell(i);
cell.setCellType(CellType.STRING);
String cellValue = cell.getStringCellValue().trim();
titleList.add(cellValue);
}
if(titleList.size()==0){
throw new DealException("000001","表中没有抬头");
}

int lastRowNum = sheet.getLastRowNum();
for (int i = startRow+1; i <=lastRowNum ; i++) {
Map<String,Object> rowDataMap= new HashMap<>();
Row rows = sheet.getRow(i);
boolean blankFlag=true;
for (int cellIndex = 0; cellIndex <titleList.size() ; cellIndex++) {
Cell cell = rows.getCell(cellIndex);
if(null==cell){
rowDataMap.put(titleList.get(cellIndex),"");
continue;
}
cell.setCellType(CellType.STRING);
String cellVal = cell.getStringCellValue().trim();
rowDataMap.put(titleList.get(cellIndex),cellVal);
if(!StringUtils.isEmpty(cellVal)){
blankFlag=false;
}
}
if(!blankFlag){
resultList.add(rowDataMap);
}
}
return resultList;

}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
这里我就不对这个工具类做具体的介绍了。
下面贴出userMapper.ftl

<?xml version="1.0" encoding="UTF-8"?>
<root>
<#list maps as map>
<user>
<#list map?keys as itemKey>
<#if itemKey=="userName">
<userName isRequired="true">${map[itemKey]}</userName>
</#if>
<#if itemKey=="telephone">
<telephone isRequired="true">${map[itemKey]}</telephone>
</#if>
<#if itemKey=="email">
<email isRequired="true">${map[itemKey]}</email>
</#if>
<#if itemKey=="birthday">
<birthday isRequired="true">${map[itemKey]}</birthday>
</#if>
<#if itemKey=="userId">
<userId isRequired="true">${map[itemKey]}</userId>
</#if>
</#list>
</user>
</#list>
</root>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
freemarker 中调用process方法,将数据模型和模板进行整合。
主要验证的代码如下

package com.example.demo.validate;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidatorAnnotion {
public String validatorType();
public String message();

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.demo.validate;

import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class TemplateValidator {
private final static String regexEmail="^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
private final static String regexPhone="^1(3|4|5|7|8)\\d{9}$";
/**
* 验证是否为电子邮箱
*@param
*@return
*/
@ValidatorAnnotion(validatorType = "isEmail",message = "邮箱格式不正确")
public static boolean isEmail(Map contentMap){
String itemValue = (String)contentMap.get("itemValue");
return isMatchString(itemValue,regexEmail,true);
}

/**
* 验证手机号码的正确性
* @param contentMap
* @return
*/
@ValidatorAnnotion(validatorType = "isPhone",message = "电话号码格式不正确")
public static boolean isPhone(Map contentMap){
String itemValue= (String) contentMap.get("itemValue");
return isMatchString(itemValue,regexPhone,true);
}

/**
* 是否是必传
* @param contentMap
* @return
*/
@ValidatorAnnotion(validatorType = "isRequired",message = "必传")
public static boolean isRequired(Map contentMap){
String itemValue = (String) contentMap.get("itemValue");
return !StringUtils.isEmpty(itemValue);
}

/**
*
* @param itemValue
* @param regex
* @param caseSentivite
* @return
*/

private static boolean isMatchString(String itemValue, String regex, boolean caseSentivite) {
boolean result=false;
if(null==itemValue||null==regex){
throw new NullPointerException("error,itemValue or regx is null");
}
Pattern pattern = null;
if(!caseSentivite){
pattern=Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
}else{
pattern=Pattern.compile(regex);
}
Matcher matcher = pattern.matcher(itemValue);
result= matcher.matches();
return result;
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.example.demo.validate;

import com.example.demo.utils.DealException;
import com.example.demo.utils.ExcelUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

public class ValidatorBeanFactory {
/**
* 默认的校验类路径
*/
private static final String DEFAULT_VALIDATE_CLASSNAME=TemplateValidator.class.getName();

static Class<?> validatorClass=null;
public static Method[] methods=null;
static{
try {
validatorClass=Class.forName(DEFAULT_VALIDATE_CLASSNAME);
methods = validatorClass.getMethods();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

public static void validate(StringBuffer buffer, Map<String,Object> attrMap) throws DealException {
boolean result=true;
for(Method method:methods){
//获取method方法上的注解
if(method.isAnnotationPresent(ValidatorAnnotion.class)){
ValidatorAnnotion annotation = method.getAnnotation(ValidatorAnnotion.class);
String validatorType = annotation.validatorType();
String attrName = (String) attrMap.get("attrName");
if(validatorType.equals(attrName)){
try {
result = (boolean) method.invoke(validatorClass, attrMap);
} catch (Exception e) {
throw new DealException("000003","参数校验异常");
}
if(!result){
buffer.append("节点").append(attrMap.get("itemName")).append(",").append(annotation.message());
}
}
}

}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example.demo.validate;

import com.example.demo.utils.DealException;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class TemplateXmlUtil {
public static String analysisXml(String xmlStr,String charset){
xmlStr= xmlStr.replaceAll("\r","");
SAXReader reader = new SAXReader();
StringBuffer sb=null;
try {
Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes(charset)));
Element xmlroot = document.getRootElement();
sb = new StringBuffer();
iteratorXml(xmlroot,sb);
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
private static void iteratorXml(Element xmlroot, StringBuffer sb) throws DealException {
Iterator<Element> iterator = xmlroot.elementIterator();
while (iterator.hasNext()){
Element xmlItem = iterator.next();
//获取属性名和属性值
List<Attribute> attributes = xmlItem.attributes();
for (Attribute attribute:attributes){
Map<String, Object> attrMap = new HashMap<>();
attrMap.put("attrName",attribute.getName());
attrMap.put("attrValue",attribute.getValue());
attrMap.put("itemName",xmlItem.getName());
attrMap.put("itemValue",xmlItem.getStringValue(http://www.my516.com));
ValidatorBeanFactory.validate(sb,attrMap);
}
iteratorXml(xmlItem,sb);
}
}
}
---------------------

利用freemarker+SAX解析xml的方式对excel文件字段校验的更多相关文章

  1. 利用django如何解析用户上传的excel文件

    https://www.jb51.net/article/119452.htm 前言 我们在工作中的时候,会有这种需求:用户上传一个格式固定excel表格到网站上,然后程序负债解析内容并进行处理.我最 ...

  2. Python—使用xml.sax解析xml文件

    什么是sax? SAX是一种基于事件驱动的API. 利用SAX解析XML文档牵涉到两个部分:解析器和事件处理器. 解析器负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件; 而事件处 ...

  3. (转)Android 创建与解析XML—— Dom4j方式 .

    转:http://blog.csdn.net/ithomer/article/details/7521605 1.Dom4j概述 dom4j is an easy to use, open sourc ...

  4. Android之SAX解析XML

    一.SAX解析方法介绍 SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备. SAX解析器是一种基于事件的解析器,事件驱动 ...

  5. DOM&SAX解析XML

    在上一篇随笔中分析了xml以及它的两种验证方式.我们有了xml,但是里面的内容要怎么才能得到呢?如果得不到的话,那么还是没用的,解析xml的方式主要有DOM跟SAX,其中DOM是W3C官方的解析方式, ...

  6. SAX解析xml浅析

    SAX解析XML文件采用事件驱动的方式进行,也就是说,SAX是逐行扫描文件,遇到符合条件的设定条件后就会触发特定的事件,回调你写好的事件处理程序.使用SAX的优势在于其解析速度较快,占用内存较少(相对 ...

  7. JavaWeb学习日记----SAX解析XML

    1.SAX解析XML文档的方式: 与DOM方式解析不同,DOM方式解析是根据XML的层级结构在内存中分配一个树形结构,把xml的标签,属性和文本都封装成对象.优点是可以很方便实现增删改操作.缺点是,如 ...

  8. Android SAX解析XML

    本篇讲解一下SAX解析XML这种方式,首先来看一下它的基本介绍: SAX是一种以事件驱动的XML API,由它定义的事件流可以指定从解析器传到专门的处理程序的代码的XML结构,简单的讲,它是种解析速度 ...

  9. Dom,pull,Sax解析XML

    本篇随笔将详细讲解如何在Android当中解析服务器端传过来的XML数据,这里将会介绍解析xml数据格式的三种方式,分别是DOM.SAX以及PULL. 一.DOM解析XML 我们首先来看看DOM(Do ...

随机推荐

  1. nginx-Proxy Cache缓存

      1.创建目录 mkdir /export/Data/nginx_proxy_cache mkdir /export/Data/nginx_proxy_temp   2.修改http,打开缓存 文件 ...

  2. 解决ubuntu中firefox浏览器总是提示找不到server的问题

    这个情况在我机器上常常出现,并且时不时的给你出点问题.可是有些时候等一下就好了.或者把引擎换到百度的话它就又行得通了.. 被这个问题搞得非常烦.上网查了下说是防火墙啊之类的出问题.可是自己弄了后这个问 ...

  3. Message: SyntaxError: unterminated string literal

    #Message: SyntaxError: unterminated string literalmytxt = words.replace('\n','').replace('\r','') js ...

  4. tracert 路由跟踪程序

    C:\Users\Administrator>tracert 10.0.0.1 通过最多 30 个跃点跟踪到 10.0.0.1 的路由 1 <1 毫秒 1 ms 3 ms 192.168. ...

  5. HDU 4850 Wow! Such String!

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4850 题意:给定一个N(1 ≤ N ≤ 500000),构造一个长度为N的小写字母字符串,要求所有长度大于 ...

  6. nestedScrollview 嵌套使用recyclerview判断滑动到底部 (嵌套滑动导致 不能使用recyclerview的onscrolled监听)

    NestedScrollView scroller = (NestedScrollView) findViewById(R.id.myScroll); if (scroller != null) { ...

  7. hdoj--1716--排列2(暴力水题)

     排列2 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  8. Net框架下-ORM框架LLBLGen的简介(转载)

    Net框架下-ORM框架LLBLGen的简介 http://www.cnblogs.com/huashanlin/archive/2015/02/12/4288522.html 官方网址:http:/ ...

  9. Linux 进程间通讯方式 pipe()函数 (转载)

    转自:http://blog.csdn.net/ta893115871/article/details/7478779 Linux 进程间通讯方式有以下几种: 1->管道(pipe)和有名管道( ...

  10. 10.24afternoon清北学堂刷题班

    /* 这是什么题... */ #include<iostream> #include<cstdio> #include<cstring> #include<q ...