项目自学记录7


项目自学记录7

对于枚举类-Stream.of()

    public static final InvoiceCatagoryEnum parse(int value) {
        return Stream.of(InvoiceCatagoryEnum.values()).filter(e -> e.value == value).findFirst().orElse(null);
    }

InvoiceCatagoryEnum.values()得到的是枚举里面的所有枚举实体类的数组,然后Stream.of()将这些数组变为流。

备注:

让我们创建整数流。

Stream<Integer> mystream = Stream.of(10, 12, 14, 16); 

假设我们迭代并打印流元素。

mystream.forEach(e -> System.out.println(e)); 

输出将为10 12 14 16。

orElse就是如果是999这种没有枚举实体类的,就给个null值返回。

@PostConstruct

该注解的方法在整个Bean初始化中的执行顺序:

Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的初始化方法)

从数据库里查出JSON数据,然后转map

import com.alibaba.fastjson.JSON;
//从数据库中取出 JSON格式的 额外变量, 然后转为MAP , 再转为 生成OFD所认可的实体类的变量名字
        VatInvoiceTdysDomain vatInvoiceTdysDomain = vatInvoiceTdysMapper.selectByFphm(invId);
        String tdysDtl = vatInvoiceTdysDomain.getTdysDtl();
        Map maps = (Map) JSON.parse(tdysDtl);

BeanUtil.copyList

hutool的beanutil,可以把一个列表转化为另一个列表,而不用写for循环了. 其底层用的是stream,其实也是for循环。

 public List<TrainQueryResp> queryAll() {
        List<Train> trainList = selectAll();
        return BeanUtil.copyToList(trainList, TrainQueryResp.class);
    }

DTO,VO的区别

Data Transfer Object和View Object

前端传数据,比如这种

selectByCondition(String userName,LocalDateTime startTime)

参数字段会变多,所以我们可以用DTO,数据传输对象,UserQueryConditionDTO【yonghu chaxun tiaojian DTO]】

后端接口就可以这样写

selectUserByCondition(@RequestBody UserQueryConditionDTO userDto)

VO,返回给视图层【前端】需要用到的对象。

比如前端想要用户的所在部门名称,我们需要一个对象封装带有deptName属性的user

关于多态的反射

B和C两个类都继承自A

A a1=new A(1);
int ran=1;
if(ran==1){
    a1=new B(2);
}else{
    a1=new C(3);
}
System.out.println(a1.getClass().getSimpleName());  //输出B

可以发现A这个类被赋值后,反射得到的类名是B。

SQL使用[CDATA[ ]]来代替转义字符大于小于号

[]中的东西不被xml解析,尽量缩小 的范围

mybatis中的 等这些标签不能写到CDATA中。否则标签将不会被mybatis解析

使用工厂模式+策略模式对版式文件生成进行优化

接口+2个实现类,就是天然的实现了策略模式。而用哪个策略,取决于工厂生成的对象是什么。

接口就是抽象策略类,接口的实现类是具体实现类。工厂生成对象写在Client类里,是上下文。

首先是抽象接口:

@FunctionalInterface
public interface IVatCreateFormatFileService {
    /**
     *  生成发票版式文件
     * @param fph  发票号
     * @param sellerCode  销货单位编码
     */
    void createFormatFile(String fph, String sellerCode);

}

有pdf和ofd两个类实现了该接口

@Service("vatCreateOfdFormatFileServiceImpl")
public class VatCreateQdOfdServiceImpl implements IVatCreateFormatFileService {
    
@Service("vatCreatePdfFormatFileServiceImpl")
public class VatLocalPdfServiceImpl implements IVatCreateFormatFileService

然后是工厂,工厂的目的是生成对象Bean,而且是以强配置的形式

@Component
public class FormatFileCreateFactory {

    private FormatFileCreateFactory() {
    }

    @Resource
    private IVatInvoiceService iVatInvoiceService;

    @Resource
    private Environment environment;

    private String getFormatFileType(int invoiceCatagory) {
        return environment.getProperty(String.format("zbiti.invoice-%d.formatfile.type", invoiceCatagory));
    }


    public IVatCreateFormatFileService getFormatFileBean(String invId) {
        //根据发票号,得到是电票 [invoiceCategory 的值为3或4] 还是 数电票[invoiceCategpry的值为5或6]
        Integer invoiceCatagory = iVatInvoiceService.selectById(invId).getInvoiceCatagory();
        //从配置文件中去取 得到formatFileType为pdf 或 ofd
        String formatFileType = getFormatFileType(invoiceCatagory);
        if (null == formatFileType) {
            return null;
        }
        //规格化一下,formatFileType1Big的值为 Pdf  或 Ofd
        String formatFileType1Big = formatFileType.substring(0, 1).toUpperCase() + formatFileType.substring(1).toLowerCase();
        return SpringUtils.getBean("vatCreate" + formatFileType1Big +"FormatFileServiceImpl");
    }

}

最后是供别的地方调用的客户端Client

@Service
public final class FormatFileCreateClient {

   @Autowired
   private FormatFileCreateFactory factory;

    public void createFormatFile(String invId, String sellerCode){
        //通过工厂得到Bean对象
        IVatCreateFormatFileService formatFileBean = factory.getFormatFileBean(invId);
        if (null != formatFileBean) {
            //Bean对象调用接口,生成版式文件
            formatFileBean.createFormatFile(invId, sellerCode);
        }
    }
}

其他类直接注入Client就可以直接调用了

@Resource
private FormatFileCreateClient formatFileCreateClient;

formatFileCreateClient.createFormatFile(invId, sellerCode)

接口中可以进行方法的实现,但要用default

Java 8 开始是可以有方法实现的,可以在接口中添加默认方法和静态方法

在 Java 8 之前,比如要在一个接口中添加一个抽象方法,那所有的接口实现类都要去实现这个方法,不然就会编译错误,而某些实现类根本就不需要实现这个方法也被迫要写一个空实现,改动会非常大。

所以,接口默认方法就是为了解决这个问题,只要在一个接口添加了一个默认方法,所有的实现类就自动继承,不需要改动任何实现类,也不会影响业务,爽歪歪。

另外,接口默认方法可以被接口实现类重写。

Java8的并行流和foreach

 strList.parallelStream().forEach(each -> {
        integerList.add(Integer.parseInt(each));
    });

这种代码是线程不安全的,如果integerList是ArrayList就是线程不安全的。

200—普通for循环数组
200—stream流for循环数组
197—parallelStream流for循环数组—会丢失数据

sql的if的有意思的地方

这样写,直接在sql里做判断。

freemarker

在12306项目里用于制作代码生成器模板,在黑马头条项目里用于生成静态的文章页面,然后存在MinIo里

读环境信息,并用String.format

# 版式文件类型 ofd,xml,pdf
# 3 电子普票
invoice-3:
  formatfile:
    type: pdf
# 4 电子专票
invoice-4:
  formatfile:
    type: pdf
# 5 数电专票
invoice-5:
  formatfile:
    CargoTransportation-type: ofd  #交通运输
    Common-type: ofd    # 普通票
    Construction-type: ofd  # 建筑服务票
    RealEstateBusinessLeasing-type: ofd # 不动产票
    Photovoltaic-type: ofd #光伏票
    Cigarette-type: ofd #卷烟
# 6 数电普票
invoice-6:
  formatfile:
    CargoTransportation-type: ofd #交通运输
    Common-type: ofd   # 普通票
    Construction-type: ofd   # 建筑服务票
    RealEstateBusinessLeasing-type: ofd  # 不动产票
    Photovoltaic-type: ofd  #光伏票
    Cigarette-type: ofd #卷烟

在销项中就是

private String getFormatFileType(int invoiceCatagory,String specialTdys) {
    return environment.getProperty(String.format("zbiti.invoice-%d.formatfile.%s-type", invoiceCatagory,StringUtils.nvl(specialTdys,"")));
}

分布式文件系统

根据枚举里的一个属性值,去查另一个属性值

本来以为要写for循环,结果发现hutool提供了工具类

第一个参数,你要得到哪列。第二个参数,你要通过哪列去查,第三个参数,第二个参数所对应的值。

BigDecimal priceRate = EnumUtil.getFieldBy(TrainTypeEnum::getPriceRate, TrainTypeEnum::getCode, trainType);
public enum TrainTypeEnum {

    G("G", "高铁", new BigDecimal("1.2")),
    D("D", "动车", new BigDecimal("1")),
    K("K", "快速", new BigDecimal("0.8"));

    private String code;

    private String desc;

    /**
     * 票价比例,例:1.1,则票价 = 1.1 * 每公里单价(SeatTypeEnum.price) * 公里(station.km)
     */
    private BigDecimal priceRate;
}

比如说trainType=”G”,则priceRate=1.2

bigDecimal的乘法,并且四舍五入

 BigDecimal ydzPrice = sumKM.multiply(SeatTypeEnum.YDZ.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);

都是几个bigDecimal相互乘,最后调整一下小数位。

一些操作,应该先清空,再重新赋值。

根据某个属性,得到枚举值

SeatTypeEnum seatTypeEnum = EnumUtil.getBy(SeatTypeEnum::getCode, seatTypeCode);

根据getCode函数的值为seatTypeCode得到枚举值

去获取一个对象的不固定的属性,就会用到反射,反射性能不如直接switch分支判断


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