#
Excel 在读取 csv 的时候是通过读取文件头上的 bom 来识别编码的,这导致如果我们生成 csv 文件的平台输出无 bom 头编码的 csv 文件(例如 utf-8 ,在标准中默认是可以没有 bom 头的),Excel 只能自动按照默认编码读取,不一致就会出现乱码问题了。
掌握了这点相信乱码已经无法阻挡我们前进的步伐了:只需将不带 bom 头编码的 csv 文件,用文本编辑器(工具随意,推荐 notepad++ )打开并转换为带 bom 的编码形式(具体编码方式随意),问题解决。
当然,如果你是像我一样的码农哥哥,在生成 csv 文件的时候写入 bom 头更直接点,用户会感谢你的。
附录:对于 utf-8 编码,unicode 标准中是没有 bom 定义的,微软在自己的 utf-8 格式的文本文件之前加上了EF BB BF三个字节作为识别此编码的 bom 头,这也解释了为啥大部分乱码都是 utf-8 编码导致的原因
SPRING BATCH中生成CSV文件时的解决方案:
new FlatFileItemWriterBuilder<T>()
.name(itemWriterName)
.resource(outputResource)
.lineAggregator(lineAggregator)
.headerCallback(
h -> {
System.out.println(header);
h.write('\uFEFF');//只需加这一行
h.write(header);
}
)
.build();
https://stackoverflow.com/questions/48952319/send-csv-file-encoded-in-utf-8-with-bom-in-java
/**
*
* @param <T>声明此方法持有一个类型T,也可以理解为声明此方法为泛型方法
* @param clazz 作用是指明泛型T的具体类型
* @return 指明该方法的返回值为类型T
* @throws InstantiationException
* @throws IllegalAccessException
*/
public <T> T getObject(Class<T> clazz) throws InstantiationException, IllegalAccessException {
T t = clazz.newInstance();//创建对象
return t;
}
方法返回值前的<T>的左右是告诉编译器,当前的方法的值传入类型可以和类初始化的泛型类不同,也就是该方法的泛型类可以自定义,不需要跟类初始化的泛型类相同
领域驱动(DDD,Domain Driven Design)为软件设计提供了一套完整的理论指导和落地实践,通过战略设计和战术设计,将技术实现与业务逻辑分离,来应对复杂的软件系统。本系列文章准备以实战的角度来介绍 DDD,首先编写领域驱动的代码模型,然后再基于代码模型,引入 DDD 的各项概念,先介绍战术设计,再介绍战略设计。
> DDD 实战1 - 基础代码模型
> DDD 实战2 - 集成限界上下文(Rest & Dubbo)
> DDD 实战3 - 集成限界上下文(消息模式)
> DDD 实战4 - 领域事件的设计与使用
> DDD 实战5 - 实体与值对象
> DDD 实战6 - 聚合的设计
> DDD 实战7 - 领域工厂与领域资源库
> DDD 实战8 - 领域服务与应用服务
> DDD 实战9 - 架构设计
> DDD 实战10 - 战略设计
@Past @Future只针对Date类型的验证,如果是String类型的验证,则不适用。
其实可以新加一个方法返回Date类型,再配合@Future@Past 进行验证。
@Future(message = "Invalid CN_ID_INFO.EXPIRE_DATE.")
private LocalDate getValidExpireDate() {
try {
return LocalDate.parse(this.dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
} catch (Exception e) {
return null;
}
}
此方法对dateString进行解释,返回LocalDate,如果dateString为空或格式错误,则返回空,再配合@Future 进行是否未来日期的验证。
bean validation的注释是针对单个变量的,如果要针对多个变量的联动,则不行,需要用到这个注释。
这种方法避免了自定义校验器而增加类。
https://www.chkui.com/article/java/java_bean_validation
@AssertTrue(message = "Missing BANK_CARD_IMG_INFO.IMG")
private Boolean getValidImg() {
if(YNEnum.Y.code.equals(super.getNeedChecked())) {
return StringUtils.hasText(this.img);
}
return null;//igore checking.
}
这个是当needChecked为Y的时候才执行检查img变量是否为空。
有几点注意:
- 方法名称要以get开头
- 返回类型用Boolean,而不用boolean
- 返回值有三种:true,false,null如果是null则当成通过,与true的结果一样
SPRING BOOT单元测试中,因为测试时可能对应的服务器地址不同于SIT等别的环境,通常会将这些地址放于application-sit.yaml中。
在单元测试的代码中用这个标签指定用哪个profile,如
@ActiveProfiles({"embedded-mongodb","test"})
但这样做法,由于@ActiveProfiles这个标签是final的,如果要测试别的profile,只能复制另一份单元测试代码,再改此标签。
比较灵活的做法是用default profile,default profile是如果没指定任何profile,则会默认用这个。在application-default.yaml中再指定需激活的profile。
spring:
profiles:
active: test,embedded-mongodb
如果要测试别的profile,可以指定环境变量的方式覆盖:
-Dspring.profiles.active=error,embedded-mongodb
为了安全起见,将application-default.yaml放在测试目录中:src\test\resources。
Setting default Spring profile for tests with override option
https://blog.inspeerity.com/spring/setting-default-spring-profile-for-tests-with-override-option/
接收数据的JAVA BEAN通常需要验证其中字段的正确性,如不准为空,符合EMAIL格式等。
JSR-303 Bean Validation则提供了这样的便捷。
只要在JAVA BEAN中需要验证的字段加@NotNull这种标签,然后在SERVISE中的输入参数中加@Valid标签,则就激活验证流程。
也可以编程的方式自己验证:
@MessageEndpoint
//@Validated
public class MqMessageCcdValidator {
private static final Logger LOGGER = LoggerFactory.getLogger(MqMessageCcdValidator.class);
@Autowired
private Validator validator;
@ServiceActivator
public MqMessage<CcdRequest> validate(/* @Valid */ Message<MqMessage<CcdRequest>> requestMessage) {
Set<ConstraintViolation<MqMessage<CcdRequest>>> set = validator.validate(requestMessage.getPayload());
if(CollectionUtils.isNotEmpty(set)) {
CompositeException compositeException = new CompositeException();
set.forEach(
constraintViolation -> {
LOGGER.info("{}", constraintViolation);
ReqInfoValidationException exception =
new ReqInfoValidationException(constraintViolation.getMessage());
compositeException.addException(exception);
}
);
throw new MessageHandlingException(requestMessage, compositeException);
}
return requestMessage.getPayload();
}
}
自定义验证规则
可用标签来做,以下为验证手机号的规则:
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import javax.validation.constraints.Pattern;
@Retention(RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Constraint(validatedBy = {})
@ReportAsSingleViolation
@Pattern(regexp = "^1[3-9]\\d{9}$")
public @interface ChinaPhone {
String message() default "Invalid Chinese mobile No.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
如果比较复杂的验证规则,则参见:
https://reflectoring.io/bean-validation-with-spring-boot/#implementing-a-custom-validatorHow to use Java Bean Validation in Spring Boot
https://nullbeans.com/how-to-use-java-bean-validation-in-spring-boot/Complete Guide to Validation With Spring Boot
https://reflectoring.io/bean-validation-with-spring-boot/Spring JMS Validate Messages using JSR-303 Bean Validation
https://memorynotfound.com/spring-jms-validate-messages-jsr-303-bean-validation/Spring REST Validation Example
https://mkyong.com/spring-boot/spring-rest-validation-example/
Spring Boot 整合 Bean Validation 校验数据
https://blog.csdn.net/wangzhihao1994/article/details/108403732