项目自学记录4
根据另外一张表中出现的次数排序
背景:
主表是风险场景,要根据风险报告中的出现次数排序,可以出现0次的
select s.scene_id, s.scene_name , count(r.scene_id) as count
from rc_scene s
left join rc_risk_report r on s.scene_id = r.scene_id
where s.company_id =100
group by s.scene_id
order by count desc
如果是不出现0次的
SELECT s.scene_id, s.scene_name
FROM rc_scene s
INNER JOIN (
SELECT scene_id , COUNT(*) as count
FROM rc_risk_report r
GROUP BY scene_id
) r ON s.scene_id = r.scene_id
where s.company_id =100
ORDER BY r.count DESC;
关于给数组添加元素(引用的问题⭐)
如果是下面这样,会导致所有添加的元素都一样
GeneratorReportVO.RcModel rcModel1=new GeneratorReportVO.RcModel();
for(RcModelDomain rc1:modelList){
BeanUtils.copyProperties(rc1,rcModel1);
rcModelList.add(rcModel1);
}
因为是引用的地址
所以应该把这个临时的new的对象放到for循环里
for(RcModelDomain rc1:modelList){
GeneratorReportVO.RcModel rcModel1=new GeneratorReportVO.RcModel();
BeanUtils.copyProperties(rc1,rcModel1);
rcModelList.add(rcModel1);
}
前端传Date失败
因为前端传的是2023-08-17的格式
所以后端要在定义类的属性的时候
@DateTimeFormat(pattern="yyyy-MM-dd")
private LocalDate birthday;
maven运行机制
我们的项目有一个启动项目(左边)和八个子模块。
在子模块里写代码,然后Intsall,然后再把主模块重新启动。
主模块的Java被编译成target下的class文件,再结合本地maven仓库里的lib库,就是项目了。
install可以把子模块里的东西搞到本地Maven的lib里。
一般不要随便刷maven,因为这是从私服里刷,可能会引入一些旧的依赖到lib里。
关于select *的一个弊端
如果数据库字段发生了改变,而实体类没变。会导致mapper的映射失败。因为查出来的东西不知道要塞到哪里去。
所以建议只写查的具体字段。
好像用map接可以避免一些问题。
生成发票的难点解决(思维问题⭐)
这个困难搞了我9天,第二周的周五才想出来。
因为要生成多页的ofd.而我手上的税局的底层模板(xml)有5个文件夹+3个xml
我唯一的多页发票是2个文件夹+3个xml
而且xml里格式也不一样。很难搞。
所以不从底层的xml下手。直接生成多个ofd,再对其进行合并。就可以得到一个多页的ofd了。
合并代码:
Path dst=Paths.get("src/main/generator/wzh.ofd");
// 2. 提供待合并文件。
Path d1Path = Paths.get("src","main","generator","wzh0.ofd");
Path d2Path = Paths.get("src","main","generator","wzh1.ofd");
// 3. 创建合并对象
try (OFDMerger ofdMerger = new OFDMerger(dst)) {
// 4. 添加合并文档和页面。
ofdMerger.add(d1Path);
ofdMerger.add(d2Path);
}
将数字double转为String
/**
* 数字格式化(四舍五入)
*
* @param value 数值
* @param digit 小数位数
* @return 字符串类型
*/
public static String format(double value, int digit) {
return String.format("%."+digit+"f",value);
}
@Transient
当想要忽略某个字段的,不让其映射数据库时候 可以使此注解@Transient
@Length
public class Student1 {
@Length(min = 1, max = 5,message = "名字不能超过5位")
String name;
}
这个校验,在controller调用的时候用.比如一个controller的函数
void func(@RequestBody @Value Student1 stu){}
要加@Value注解,则会校验前端传过来的数据,不满足长度规则,则不会执行方法体内的方法,返回报错异常。
@Pattern
写正则表达式,下面的值必须满足正则表达式的规则
@NotNull(message = "蓝字发票标志不可为空")
@Pattern(regexp = "[01]", message = "蓝字发票标志只能是 0:蓝字发票,1:红字发票")
private String lzfpbz;
名称(中文字符、 字母、数字)
@Pattern(regexp="^[\u4e00-\u9fa5_a-zA-Z0-9]+$",message="公司名称只能输入中文字符 字母、数字")
private String name;
用户名必须要有一个小写字母,一个大写字母和一个数字,并且是6-20位
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[A-Za-z0-9]{6,20}$", message = "用户名错误")
其他正则表达式,诸如数字校验,字符串校验,月份时间校验,Email校验,汉字校验,联系电话校验,密码校验。可以看这篇文章
关于子类重写属性变量一事
如果是同名但是不同属性值,是不行的。
会生成两个getList方法,并且返回类型不一样。一个是返回List
即使当时的业务场景是good2 extends good1,也不行
Error:(10, 17) java: me.Son中的getList()无法覆盖me.Father中的getList()
返回类型java.util.List<me.good2>与java.util.List<me.good1>不兼容
所以说,不能同名。
子类反射的结果
@Test
public void test5(){
Father f1=new Son();
System.out.println(f1.getClass().getSimpleName());
//Son
}
子类反射得到的类,还是子类。
不用instanceof写if-else,用反射+策略模式+自定义函数式接口(⭐⭐⭐⭐⭐)
interface CustomBiConsumer<T, U> {
void accept(T t, U u) throws IOException;
}
public final class FapiaoOfdClient {
//实例级配置
private InstanceConfiguration configuration;
/**
* 私有构造函数
*/
private FapiaoOfdClient() {
configuration = InstanceConfiguration.getInstance();
}
/**
* 获取实例化后的单例对象
* @return 电子发票OFD客户端
*/
public static FapiaoOfdClient getInstance() {
return new FapiaoOfdClient();
}
private HashMap<String, CustomBiConsumer<EInvoiceDomain, ZipOutputStream>> map=new HashMap<>();
public void beforeCreateOfd(){
//这里创建一个instance的目的是:不让createOfd声明为static函数
BasicServiceFaPiaoOfdClient instance = BasicServiceFaPiaoOfdClient.getInstance();
map.put("EInvoiceDomain",instance::createOfd);
}
/**
* 创建OFD文件
*
* @param invoiceInfoDomain 发票信息
* @param zos 输出流
* @throws IOException IO异常
*/
public void createOfd(EInvoiceDomain invoiceInfoDomain, ZipOutputStream zos) throws IOException {
beforeCreateOfd();
String category=invoiceInfoDomain.getClass().getSimpleName();
map.get(category).accept(invoiceInfoDomain,zos);
}
}
首先自定义了一个函数式接口(Java8新特性),两个参数CustomBiConsumer
这个函数式接口作为hashMap的value值
然后往hashmap里塞值,key: 类名(字符串) value: 函数
通过反射得到对象的类名
然后根据hashmap和key值来调用对应的value值,也就是对应的函数。
以下红色的是我写的核心代码
后面有什么新增的类,直接在beforeCreateOfd()里增加两行代码就行。不用修改其他的代码。