导入excel使用hibernate validator进行字段校验

导入excel使用hibernate validator进行字段校验

背景:平时项目中一般都会有excel导入的功能,那么就需要校验excel中的字段是否符合要求,保证功能的健壮性。

进入主题,我们使用hibernate validator 进行excel字段的校验。Hibernate Validator  Bean Validation 的参考实现 , Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint

Hibernate Validator 的使用

1.     引入jar包

可以单独引入 hibernate validator 的maven依赖,也可以使用springboot 的方式引入spring-boot-starter-web,该starter包里边包含hibernate-validator 包

2.     Java对象添加约束注解

我们将excel导入系统中,使用Java对象进行接收,在Java对象属性添加约束注解。

例子:

        @NotBlank

        @NotNull

        @Max(10)

        @Min(0)

        @Pattern(regexp=”[A-Z][a-z][0-9]”)

这样的基本注解有很多,详情可以查看hibernate-validator官网

有时候框架提供的校验注解(constraint)并不能满足我们的需求,比如我们需要验证一个字段存不存在数据库中;这时就需要用到自定义constraint

编写自定义constraint

1) 注解上必须有 @Constraint(validatedBy = {******.class}) 注解标注,validateBy 的值就是校验逻辑的实现类,实现类必须实现接口ConstraintValidator

2) 自定义注解 必须包含 message ,groups,payload 属性。

详情请看附件ChannelNbrIsExist.java注解类

3.     封装工具类在代码中校验

封装一个validationUtil 工具类,详情请看validationUtil.java

4.     Service 中使用validationUtil工具类进行Java对象的校验,如果校验失败,会返回错误信息,开发者可以将错误信息返回前台,提示用户错误信息,重新上传excel文件。

package com.lc.walrus.channelcenter.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;

import org.hibernate.validator.HibernateValidator;

import lombok.Data;

/**
 * 校验工具类
 * 
 * @author li
 */
public class ValidationUtil {

	/**
	 * 	快速结束模式 failFast(true)
	 */
	private static Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(true)
			.buildValidatorFactory().getValidator();
	
	/**
	 *   校验对象
	 * @param t bean
	 * @param groups 校验组
	 * @return ValidResult
	 */
	public static <T> ValidResult validateBean(T t,Class<?>...groups) {
		ValidResult result = new ValidationUtil().new ValidResult();
		Set<ConstraintViolation<T>> violationSet = validator.validate(t, groups);
		boolean hasError = violationSet != null && violationSet.size() > 0;
		result.setHasErrors(hasError);
		if (hasError) {
            for (ConstraintViolation<T> violation : violationSet) {
                result.addError(violation.getPropertyPath().toString(), violation.getMessage());
            }
        }
        return result;
	}
	
	/**
	 * 	校验bean的某一个属性
	 * @param obj			bean
	 * @param propertyName  属性名称
	 * @return ValidResult
	 */
	public static <T> ValidResult validateProperty(T obj, String propertyName) {
        ValidResult result = new ValidationUtil().new ValidResult();
        Set<ConstraintViolation<T>> violationSet = validator.validateProperty(obj, propertyName);
        boolean hasError = violationSet != null && violationSet.size() > 0;
        result.setHasErrors(hasError);
        if (hasError) {
            for (ConstraintViolation<T> violation : violationSet) {
                result.addError(propertyName, violation.getMessage());
            }
        }
        return result;
    }

	/**
	 * 校验结果类
	 */
	@Data
	public class ValidResult {

		/**
		 * 是否有错误
		 */
		private boolean hasErrors;
		/**
		 * 错误信息
		 */
		private List<ErrorMessage> errors;
		
	    public ValidResult() {
            this.errors = new ArrayList<>();
        }
        public boolean hasErrors() {
            return hasErrors;
        }

        public void setHasErrors(boolean hasErrors) {
            this.hasErrors = hasErrors;
        }
        /**
         * 	获取所有验证信息
         * @return 集合形式
         */
        public List<ErrorMessage> getAllErrors() {
            return errors;
        }
        /**
         * 	获取所有验证信息
         * @return 字符串形式
         */
        public String getErrors(){
            StringBuilder sb = new StringBuilder();
            for (ErrorMessage error : errors) {
               // sb.append(error.getPropertyPath()).append(":").append(error.getMessage()).append(" ");
            	sb.append(error.getMessage());
            }
            return sb.toString();
        }

        public void addError(String propertyName, String message) {
            this.errors.add(new ErrorMessage(propertyName, message));
        }
	}

	@Data
	public class ErrorMessage {

		private String propertyPath;

		private String message;

		public ErrorMessage() {
		}

		public ErrorMessage(String propertyPath, String message) {
			this.propertyPath = propertyPath;
			this.message = message;
		}
	}

}
package com.lc.walrus.channelcenter.busi.resources.service.impl;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.jxls.reader.ReaderBuilder;
import org.jxls.reader.XLSReadStatus;
import org.jxls.reader.XLSReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.plugins.Page;
import com.lc.walrus.channelcenter.busi.base.Const;
import com.lc.walrus.channelcenter.busi.resources.constant.Constant;
import com.lc.walrus.channelcenter.busi.resources.dto.QryResourceDTO;
import com.lc.walrus.channelcenter.busi.resources.dto.ResourceDTO;
import com.lc.walrus.channelcenter.busi.resources.dto.ResourcesDTO;
import com.lc.walrus.channelcenter.busi.resources.entity.ChannelResourcesRel;
import com.lc.walrus.channelcenter.busi.resources.entity.ResourcesUsedInfo;
import com.lc.walrus.channelcenter.busi.resources.service.IChannelResourcesRelService;
import com.lc.walrus.channelcenter.busi.resources.service.IResourcesService;
import com.lc.walrus.channelcenter.busi.resources.vo.ResourceUsedInfoVO;
import com.lc.walrus.channelcenter.config.ChnviewConfig;
import com.lc.walrus.channelcenter.mapper.combusi.ComBusiMapper;
import com.lc.walrus.channelcenter.mapper.resources.ResourcesMapper;
import com.lc.walrus.channelcenter.mapper.resources.ResourcesUsedInfoMapper;
import com.lc.walrus.channelcenter.util.JxlsUtil;
import com.lc.walrus.channelcenter.util.ValidationUtil;
import com.lc.walrus.channelcenter.util.ValidationUtil.ValidResult;

import lombok.extern.slf4j.Slf4j;

/**
 * @Auther: 
 * @Date: 2019/7/22
 * @Description: 
 */
@Service
@Transactional
@Slf4j
public class ResourcesServiceImpl implements IResourcesService {

	private static final String TEMPLATE_FILE_NAME_XML = "ChannelResourcesRel.xml";
	private static final String TEMPLATE_FILE_NAME = "resourcesUsed.xls";
	private static final String DOWNLOAD_FILE_NAME = "资源领用导入模板.xls";

	@Autowired
	private IChannelResourcesRelService channelResourcesRelService;

	@Autowired
	private ResourcesMapper resourcesMapper;

	@Autowired
	private ResourcesUsedInfoMapper resourcesUsedInfoMapper;

	@Autowired
	private ComBusiMapper comBusiMapper;

	@Override
	public Page<Map<String, Object>> qryResUsedPageList(Page<Map<String, Object>> page, QryResourceDTO qryResourceDTO) {
		if (null == page) {
			page = new Page<Map<String, Object>>(Const.DEF_CURRENT_PAGE, Const.DEF_PAGE_SIZE);
		}
		return page.setRecords(resourcesMapper.qryResUsedPageList(page, qryResourceDTO));
	}

	@Override
	public List<Map<String, Object>> queryResourceType(String resourceType) {
		return resourcesMapper.queryResourceType(resourceType);
	}

	@Override
	public List<Map<String, Object>> qryResourcesByType(ResourcesDTO resources) {
		return resourcesMapper.qryResourcesByType(resources);
	}

	@Override
	public List<Map<String, Object>> qryTempResources(ResourcesDTO resources) {
		return resourcesMapper.qryTempResources(resources);
	}

	@Override
	public Long saveResourceAndGoPay(ResourcesDTO resources) throws Exception {
		// 生成资源领用单主键 和 关联主键
		Long resourcesUsedInfoId = comBusiMapper.getCommonBusiSeqId(new HashMap());
		String relCode = comBusiMapper.getCommonBusiSeqId(new HashMap()) + "";
		ResourcesUsedInfo info = new ResourcesUsedInfo();
		info.setId(resourcesUsedInfoId);
		info.setRelCode(relCode);
		info.setTypesName(getResourcesName(resources.getSelectResources()));
		info.setStatusCd(Constant.TO_PAY + "");
		BeanUtils.copyProperties(info, resources);
		resourcesUsedInfoMapper.insert(info);

		List<ChannelResourcesRel> list = new ArrayList<>();
		ChannelResourcesRel channelResourcesRel;
		List<ResourceDTO> resourceSelList = resources.getResourceSelList();
		if (resourceSelList != null && resourceSelList.size() > 0) {
			for (ResourceDTO resource : resourceSelList) {
				Long channelResourcesRelId = comBusiMapper.getCommonBusiSeqId(new HashMap());
				channelResourcesRel = new ChannelResourcesRel();
				channelResourcesRel.setId(channelResourcesRelId);
				channelResourcesRel.setRelCode(relCode);
				channelResourcesRel.setChannelNbr(resources.getChannelNbr());
				channelResourcesRel.setResourceId(resource.getResourceId());
				channelResourcesRel.setResourcePriceReal(resource.getResourcePrice());
				channelResourcesRel.setResourceNumReal(resource.getResourceNumReal());
				channelResourcesRel.setResourceTotal(resource.getResourceTotal());
				channelResourcesRel.setCreateStaff(resources.getCreateStaff());
				channelResourcesRel.setUpdateStaff(resources.getUpdateStaff());
				list.add(channelResourcesRel);
			}
		}
		channelResourcesRelService.insertBatch(list);

		return resourcesUsedInfoId;
	}

	@Override
	public void useResources(String resourceUsedId) {
		ResourcesUsedInfo info = resourcesUsedInfoMapper.selectById(resourceUsedId);
		info.setStatusCd(Constant.USEING + "");
		info.setStatusDate(LocalDateTime.now());
		resourcesUsedInfoMapper.updateById(info);
	}

	private String getResourcesName(String[] selectResources) {
		List<String> names = resourcesMapper.qryResourcesNames(selectResources);
		return StringUtils.join(names, ",");
	}

	@Override
	public ResourceUsedInfoVO qryResUsedDetail(String resourceUsedId) {
		return resourcesMapper.qryResUsedDetail(resourceUsedId);
	}

	@Override
	public void doPayResource(String resourceUsedId) {
		ResourcesUsedInfo info = resourcesUsedInfoMapper.selectById(resourceUsedId);
		info.setPayTime(LocalDateTime.now());
		info.setStatusCd(Constant.TO_USE + "");
		resourcesUsedInfoMapper.updateById(info);
	}

	@Override
	public Long retResources(ResourcesDTO resources) {
		String resourceUsedId = resources.getResourceUsedId();
		ResourcesUsedInfo info = resourcesUsedInfoMapper.selectById(resourceUsedId);
		info.setReturnNum(resources.getResourceNum());
		info.setReturnMoney(resources.getReturnMoney());
		info.setStatusCd(Constant.TO_REFUND + "");
		// 如果是赊付,则更新为 回退完成 状态
		if (info.getIsCredit().equals(Constant.CREDIT_Y + "")) {
			info.setStatusCd(Constant.RETURND + "");
		}
		info.setStatusDate(LocalDateTime.now());
		info.setUpdateDate(LocalDateTime.now());
		info.setUpdateStaff(resources.getUpdateStaff());
		resourcesUsedInfoMapper.updateById(info);

		List<ResourceDTO> resourcesList = resources.getResources();
		List<ChannelResourcesRel> list = new ArrayList<>();
		for (ResourceDTO res : resourcesList) {
			ChannelResourcesRel channelResourcesRel = channelResourcesRelService
					.selectById(res.getChannelResourcesRelId());
			channelResourcesRel.setReturnNum(res.getReturnNum());
			channelResourcesRel.setReturnMoney(res.getReturnMoney());
			channelResourcesRel.setReturnDate(LocalDateTime.now());
			channelResourcesRel.setUpdateDate(LocalDateTime.now());
			channelResourcesRel.setUpdateStaff(resources.getUpdateStaff());
			list.add(channelResourcesRel);
		}
		channelResourcesRelService.updateBatchById(list);
		return info.getId();
	}

	@Override
	public Long refundResources(ResourcesDTO resources) {

		String resourceUsedId = resources.getResourceUsedId();
		ResourcesUsedInfo info = resourcesUsedInfoMapper.selectById(resourceUsedId);
		// 减去回退的资源数量
		info.setResourceNum(info.getResourceNum() - info.getReturnNum());
		// 减去回退的款项
		info.setResourceTotal(info.getResourceTotal().subtract(info.getReturnMoney()));
		// 状态 回退完成
		info.setStatusCd(Constant.RETURND + "");
		// 状态时间
		info.setStatusDate(LocalDateTime.now());
		// update date
		info.setUpdateDate(LocalDateTime.now());
		// update staff
		info.setUpdateStaff(resources.getUpdateStaff());
		resourcesUsedInfoMapper.updateById(info);

		List<ResourceDTO> resourcesList = resources.getResources();
		List<ChannelResourcesRel> list = new ArrayList<>();
		for (ResourceDTO res : resourcesList) {
			ChannelResourcesRel channelResourcesRel = channelResourcesRelService
					.selectById(res.getChannelResourcesRelId());
			channelResourcesRel.setResourceNumReal(res.getResourceNumReal() - res.getReturnNum());
			channelResourcesRel.setResourceTotal(res.getResourceTotal().subtract(res.getReturnMoney()));
			channelResourcesRel.setStatusCd(Constant.RETURND + "");
			channelResourcesRel.setStatusDate(LocalDateTime.now());
			channelResourcesRel.setUpdateDate(LocalDateTime.now());
			channelResourcesRel.setUpdateStaff(resources.getUpdateStaff());
			list.add(channelResourcesRel);
		}
		channelResourcesRelService.updateBatchById(list);
		return info.getId();
	}

	@Override
	public void downloadExcel() {
		Page<Map<String, Object>> page = new Page<>(1, Integer.MAX_VALUE);
		List<Map<String, Object>> records = resourcesMapper.queryResourcesByPage(page);
		JxlsUtil.exportListDataA(records, TEMPLATE_FILE_NAME, DOWNLOAD_FILE_NAME);
	}

	@Override
	public List<ChannelResourcesRel> getExcelData(MultipartFile excelFile) {
		List<ChannelResourcesRel> channelResourcesRelList = new ArrayList<ChannelResourcesRel>();
		try {
			InputStream inputXML = JxlsUtil.class
					.getResourceAsStream(ChnviewConfig.jxlsWorkSheetXMLPath + File.separator + TEMPLATE_FILE_NAME_XML);
			XLSReader mainReader = ReaderBuilder.buildFromXML(inputXML);
			InputStream inputXLS = new BufferedInputStream(excelFile.getInputStream());
			ChannelResourcesRel channelResourcesRel = new ChannelResourcesRel();
			Map<String, Object> beans = new HashMap<String, Object>();
			beans.put("channelResourcesRel", channelResourcesRel);
			beans.put("channelResourcesRelList", channelResourcesRelList);
			XLSReadStatus readStatus = mainReader.read(inputXLS, beans);
			if (readStatus.isStatusOK()) {
				System.out.println("jxls读取Excel成功!");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return channelResourcesRelList;
	}
	
	

	@Override
	public Map<String, Object> checkData(List<ChannelResourcesRel> channelResourcesRelList) {
		
		Map<String, Object> resultMap = new HashMap<String, Object>();
		if(channelResourcesRelList == null || channelResourcesRelList.size() == 0) {
			resultMap.put("error", "导入的excel为空");
			return resultMap;
		}
		for (int i = 0 ; i < channelResourcesRelList.size() ; i ++) {
			ChannelResourcesRel rel = channelResourcesRelList.get(i);
			ValidResult result = ValidationUtil.validateBean(rel);
			
			if(result.hasErrors()) {
				String error = "第" + (i + 3) + "行" + result.getErrors();
				resultMap.put("error", error);
				System.out.println(error);
				return resultMap;
			}
		}
		
		return null;
	}

	@Override
	public Map<String, Object> fetchTempResources(List<ChannelResourcesRel> channelResourcesRelList) {
		Map<String, Object> result = new HashMap<String, Object>();
		// 提取出 渠道信息
		ChannelResourcesRel rel = channelResourcesRelList.get(0);
		Map<String, Object> channelInfo = resourcesMapper.queryChannelInfoByChannelNbr(rel.getChannelNbr());
		result.put("channelInfo", channelInfo);
		
		//提取出资源列表
		Set<ChannelResourcesRel> set = new HashSet<ChannelResourcesRel>();
		for (ChannelResourcesRel channelResourcesRel : channelResourcesRelList) {
			set.add(channelResourcesRel);
		}
		List<Map<String, Object>> tempResources = resourcesMapper.qryTempResourcesBySet(set);
		result.put("resources", tempResources);
		return result;
	}


}
package com.lc.walrus.channelcenter.busi.resources.validation;

import javax.annotation.PostConstruct;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.walrus.channelcenter.mapper.resources.ResourcesMapper;

/**
 * 校验渠道编码是否存在
 * @author l
 */
@Component
public class ChannelNbrValidator implements ConstraintValidator<ChannelNbrIsExist, String>{

	@Autowired
	private ResourcesMapper resourcesMapper;
	
	private static ResourcesMapper sResourcesMapper;
	
	/**
	 * 校验逻辑
	 */
	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
		Integer result = sResourcesMapper.checkChannelNbrIsExists(value);
		return result > 0;
	}

	@PostConstruct
	public void init() {
		sResourcesMapper = resourcesMapper;
	}

}
package com.walrus.channelcenter.busi.resources.validation;

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

import javax.validation.Constraint;
import javax.validation.Payload;

/**
 * 检验excel 中 ChannelNbr是否存在数据库
 * @author 
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ChannelNbrValidator.class)
public @interface ChannelNbrIsExist {
	
	String message() default "渠道编码不存在";
	/**
     * 必须的属性
     * 用于分组校验
     */
    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

/** * 此代码是完成从excel导入电话号码,将正确的电话号码保存到set集合中,因为set集合对于重复的值会覆盖,所以达到了去重复的值的用例,并累计了不正确的电话号码的个数,对电话号码进行了验证有效性。所需要的 dom4j-1.6.1.jar;geronimo-stax-api_1.0_spec-1.0.jar;poi-3.7-20101029.jar;poi-ooxml-3.7-20101029.jar;poi-ooxml-schemas-3.7-20101029.jar;xmlbeans-2.3.0.jar; */ public static void main(String[] args) { Long errorMobileTotal=0L; // 保存正确的电话号码 Set<String> mobileSet = new HashSet<String>(); try { XSSFWorkbook wb = new XSSFWorkbook("E:/workbook1.xlsx"); XSSFSheet sheet = wb.getSheetAt(0); XSSFRow row = null; XSSFCell cell = null; String mobileStr=""; for (int i = 0; i <= sheet.getLastRowNum(); i++) { row = sheet.getRow(i); //System.out.print("第" + i + "行共" + row.getLastCellNum() +"列: "); for (int y = 0; y < row.getLastCellNum(); y++) { cell = row.getCell(y); // 设置字段为字符类型 cell.setCellType(XSSFCell.CELL_TYPE_STRING); // 判断储存格的格式 if (cell != null) { // 取得单元格的值 mobileStr = cell.getStringCellValue(); // 对手机号码进行验证身份正确 if(isMobileNO(mobileStr)) { // 保存正确的手机号码 mobileSet.add(mobileStr); System.out.println("号码"+mobileStr+"正确"); } else { // 累计不正确的电话号码的个数 errorMobileTotal++; System.out.println("不正确的电话号码个数:"+errorMobileTotal); System.out.println("号码"+mobileStr+"不正确"); } } // end (cell != null) }// end 遍历当前行 } // end 遍历当前工作单元sheet System.out.println("总共的行数:"+ (Long.valueOf(sheet.getLastRowNum())+1)); } catch (Exception e) { e.printStackTrace(); } // 因为要去除重复的所以可能有存在替换的字符 System.out.println("不正确的电话号码个数:"+errorMobileTotal); System.out.println("正确的电话号码个数:" + mobileSet.size()); } public static boolean isMobileNO(String mobiles){ Pattern p = Pattern.compile("^(\\+86)*0*((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$"); Matcher m = p.matcher(mobiles); return m.matches(); }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值