项目自学记录8
断言的使用
断言在判断非空
AssertUtils.assertNotNull(bean, "缺失bean对象,name=" + beanName);
AssertUtils.assertNotNull(formatFile, "版式文件生成失败");
调用本类方法,其事务不生效
所以要新增一个类去调用别的类的方法。
数据库建表时关于varchar(256)与varchar(255)的讨论
在4.0版本以下,varchar(255)指的是255个字节,使用1个字节存储长度即可。当大于等于256时,要使用2个字节存储长度。所以定义varchar(255)比varchar(256)更好。
但是在5.0版本以上,varchar(255)指的是255个字符,每个字符可能占用多个字节,例如使用UTF8编码时每个汉字占用3字节,使用GBK编码时每个汉字占2字节。
NOTE:在生产环境我们一般用utf8mb4字符集。
文件路径要使用’/‘而不是’\\‘
对于linux系统,盘符不是\\,而是/
然后用/的话本地跑不起来,要用File.separator
二选一的注入
首先写了一个配置类
@Configuration
public class KaptchaConfig {
@Bean
public DefaultKaptcha getDefaultKaptcha() {
}
@Bean
public DefaultKaptcha getWebKaptcha(){}
}
然后在controller中是这么注入的
@RestController
@RequestMapping("/kaptcha")
public class KaptchaController {
@Qualifier("getDefaultKaptcha")
@Autowired
DefaultKaptcha defaultKaptcha;
}
访问jar包内的资源-打jar包后访问资源失败
jar包内的,我们得到的路径
file:\D:\developer_tools\repository\com\zbiti\anvil\vat\tools\ofd\invoice-ofd-creator\2.1.0-SNAPSHOT\invoice-ofd-creator-2.1.0-SNAPSHOT.jar!\shui.png
在子模块独立运行我们得到的路径
file:/D:/company/zbiti-sdk-ofd-v2/target/classes/shui.png
因为jar包下有.jar!,这个冒号,导致一般的文件或者文件名,可能会导致打开失败。
应该直接用流去做。(Java的流实在是tql)当然中间也可以用类加载器。
private byte[] getQrImageData() throws IOException {
String content = invoiceInfoDomain.getGraphCode();
BufferedImage image = null;
InputStream resource = DocumentResXmlCreater.class.getClassLoader().getResourceAsStream("shui.png");
if (!Objects.isNull(resource) ) {
image = ZXingQRCodeUtils.createQRCodeWithLogo(content,resource);
} else {
image = ZXingQRCodeUtils.createQRCode(content);
}
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ImageIO.write(image, "png", bao);
return bao.toByteArray();
}
这样可以保证在ofd-v2的测试程序和vat-back里有jar包的情况下都可以运行。
如何在外面给一个类的内部类赋值
public class OuterClass {
private int outerVariable = 10;
public class InnerClass {
private int innerVariable = 20;
public void setInnerVariable(int value) {
this.innerVariable = value;
}
public int getInnerVariable() {
return innerVariable;
}
}
public InnerClass getInnerClassInstance() {
return new InnerClass();
}
}
public class Main {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
// 获取内部类的实例
OuterClass.InnerClass inner = outer.getInnerClassInstance();
// 修改内部类的变量
inner.setInnerVariable(30);
// 输出内部类的变量
System.out.println(inner.getInnerVariable()); // 输出:30
}
}
里面写一个getInnerClassInstance。不然外面不能直接设置内部类里的属性。
selectByMap()要用invId,而不是inv_id
要用类字段而不是数据库字段
当然还是要看底层sql是咋写的。
在一些文件中,调用数组的size之前,也应该判断是否为Null
排查空指针异常的时候发现的。
在一个底层函数里面写了for(i = 0; i < vatInvoiceXMLDomain.getUndefinedLabelList().size(); ++i)
结果null指针。因为这个List压根没赋值。
应该先判断这个List是否为Null
所有三段的,都要判断中间那个变量是否为Null
比如这种
+vatInvoiceXMLDomain.getTaxSupervisionInfo().getInvoiceNumber()
要判断
vatInvoiceXMLDomain.getTaxSupervisionInfo()!=null
如果打断点失败,应该重启
打断的变灰,说明项目走不到这里。应该重启让他重新编译一下。
数据库插入数据,如果需要删除旧数据,使用replace into
不要用update,尤其是在有自增主键的情况下。
replace into 判断数据是否”存在”的机制是:被插入的数据是否违反主键索引
或者唯一键索引
约束。如果两者都没有违反的话,就进行插入操作,如果有违反的话,就会执行”替换”操作,这里的替换所做的事情是:先删除,在插入
。
删除:删除所有会产生以上所说的冲突的数据行。
插入:此时可以将 replace into 看成 insert into 语句。
replace into 和 insert into on duplicate key update 的区别
但是也要考虑其他的业务方面的一致性
解决跨包调用问题,使用接口
上面想调用下面,调用失败。则建立一个接口,让上面的类调用上面的接口。下面的类实现上面的接口。
Pgsql的时间做减法
因为服务器上时间是错误的,所以要在Java本地去new Date(),然后以nowDate为参数名字传入sql中。
Cause: org.postgresql.util.PSQLException: ERROR: operator does not exist: timestamp without time zone < interval
项目用的 PostgreSQL 数据库,使用 SpringBoot + Mybatis 整合
where main.create_time (#{nowDate} - INTERVAL ‘1 minute’);报错
改为下面这种,要加::timestamp才能做减法
where main.create_time <![CDATA[<]]> #{nowDate}::timestamp - interval '1 minute';
对页面的表格数据变为Excel下载
@RequestMapping("/exportInvoiceList")
public void exportData(IntaxInvoiceDTO intaxInvoiceDTO, HttpServletRequest request, HttpServletResponse response) throws IOException {
List<IntaxInvoiceVO> dataList =intaxInvoiceService.exportInvoiceList(intaxInvoiceDTO);
ExcelUtils.exportExcel(String.format("异常开票管理-%s", DateUtils.getCurrentDateTimeStrWithoutSplit()), "异常发票数据", dataList,IntaxInvoiceVO.class, request, response);
}
最核心的就是ExcelUtils.exportExcel函数,第三个参数,数据列表,第四个参数,这个数据属于哪个类。
/**
* 导出Excel(单Sheet页数据)
*
* @param fileName 文件名
* @param sheetName Sheet页名
* @param data 导出的数据
* @param clazz 类型
* @param request 请求
* @param response 响应
* @param <T> 类型模板
* @throws IOException IO异常
*/
public static <T> void exportExcel(final String fileName, final String sheetName, final List<T> data, final Class<T> clazz, final HttpServletRequest request, final HttpServletResponse response) throws IOException {
ExcelSheetDomain<T> excelSheetDomain = new ExcelSheetDomain<>(sheetName, data, clazz);
exportExcel(fileName, excelSheetDomain, request, response);
}
然后整个文件在vat-base里的ExcelUtils。