项目自学记录4


项目自学记录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, 一个是返回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()里增加两行代码就行。不用修改其他的代码。


文章作者: 爱敲代码の鱼儿
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 爱敲代码の鱼儿 !
  目录