java开发杂项总结

文章目录

  • java开发小白杂项总结
    • 一、java
        • 1.java8新特性
          • (1)stream流式操作
        • 2.static使用(与属性注入的关系)
          • (1)static(主函数是static修饰)只能调用调用static方法
          • **(2) 静态内部类**(从类的加载顺序可知【加载原则先静态后非静态,先父类再子类】)
        • 3.集合
          • (1)List中add和addAll的区别
        • 4.java常用API(常看api文档)
          • 1.集合(工具类)
          • 2.Arrays
          • 3.Collections
        • 5.IO流
        • 6.java自带util
    • 二、Mysql
        • 1)外连接查询/函数运用到相应的列
        • 2)模糊查询写法
        • 3)foreach/trim区别
        • 4)Mybatis插入list集合
        • 5)关联查询
            • 5.1.sql左联右联的差别
        • 6)嵌套查询
        • 7)distinct关键字去重
    • 三、Spring全家桶
        • 1.注解
        • 2.OpenFeign的使用
          • 理解feign的代码架构方式
        • 3.@Scheduled定时任务cron表达式
        • 4.配置文件的使用
    • 四、Mybatis
        • 1、传参问题
      • 2、result问题
        • 3、异常
        • 4.sql片段的使用
        • 5、trim剪切标签的使用
    • 五、异常总结
        • 1)数据截断异常
        • 2)BadSqlGrammarException(只要报这个异常,直接将语句放到数据库调试)
        • 3)result问题
        • 4)异常
        • 5)java.lang.IllegalArgumentException: Pattern cannot be null or empty
        • 6)feign.FeignException$NotFound: [404] during [POST]
    • 六、第三方开发工具的使用
        • 1.xshell的使用(linux常用命令行)
        • 2.xxlJob分布式定时任务的使用
        • 3.redis使用
            • Can't connect to redis-server
        • 4.Jrebel热部署(提高开发效率)
    • 七、中间件的使用
        • 1.nacos官方文档
    • 八、开发中Problem
      • 1)spring中使用Junit测试
          • 1、导入Junit依赖
      • 2)代码规范
      • 3)分装json对象
      • 4)发送Http请求/获取httpRequest和httpResponse
      • 5)封装对象,
      • 6)BigDecimal类型转化千万不能强制类型转换(精度丢失,详见阿里开发手册),转化(元,分,厘)【无非就是简单的乘除操作】
      • 7)String 的正则表达式
      • 8)pom文件引用的坑,用于抽取API模块时,依赖引用问题
      • 9)前后端文件传输
      • 10)枚举类和属性类的区别
      • 11)list.foreach的实际应用
      • 12)巧用三元运算符
      • 13)Date格式
      • 14)excel导入导出
      • 15)DTO和VO的区别
      • 16)开发工具安装问题,程序扫描
      • 17)配置文件
      • 18)接不到参数为空,原因
      • 19)为了再nacos中起不一样的服务,避免开发冲突(其中在调用方也需要配置调用方)
      • 20)数据库设计,时间自动增长,和插入的时间有关
      • 21)转化请求的时间格式
      • 22)在类中使用静态变量(定义常量)和方法(日常写法)
      • 23)private和public修饰属性的区别
      • 24)数据库和mq的了解
      • 25)MultipartFile文件流,前后端交互
      • 26)jenkens部署,发送代码时,记得发布到测试环境
      • 27)使用mybatisplus Wrapper层的作用
      • 28)经常需要的时间戳(13位),获取毫秒
      • 29)初识配置nacos
      • 30)读取配置类中的值,配置类写法
      • 31)项目中的yml配置nacos中的配置
      • 32)nacos中的配置,对标上面的配置
      • 33)postman怎么传json格式
      • 34)java后端强行转时间格式
      • 35)分页代码
      • 36)将字符串(string)转化为相应的数据类型的集合(List)
      • 37)前端没有长整型,都是string
      • 38)限制文件上传大小,添加配置文件
      • 39)全局版本号的定义(父子工程pom文件的书写)
      • 40)swagger接口文档的注意事项
      • 41)api中要求url拼接的参数形式(以钉钉发送消息模板发送data为例)
      • 42)拼接固定参数url,java Api(StrSubstitutor)指定字符拼接,${}符号中的占位符
      • 43)SpringCloud Feign 传参问题及传输Date类型参数的时差(未能解决,换了方法)
      • 44)sql语句优化(数据库优化,待学习)
          • 1.查看sql执行过程
          • 2.结果
      • 45)java8新特性对比(流的方式拿出集合中对应的指定属性,写法上的优化)
      • 46)JAVA中常量使用常量类或者常量接口,还是使用枚举的区别
      • 47)浮点数之间的等值判断,不能使用==或equals使用方法
      • 48)各种数据类型之间的比较方法选用【==和equals并不是全部适用的】(阿里巴巴见开发手册)
      • 49)遍历map集合的(4+1种)【还有一个事java8:map.forEach】
      • 50)一边循环一边删除集合中的数据(必须使用迭代器,不能使用forEach)
      • 51)递归拿捏(迷宫问题,理解小测试)
      • 52)专业词汇类目,spu,sku
      • 53)sql模糊搜索,索引问题
      • 54)说说count(*)、count(1)、count(列名)有什么区别?
      • 55)xml多条件模糊查询
      • 56)url拼接
      • 57)MyBatisPlus多条件查询,组合查询
      • 58)前后端交互Long和string
      • 56)url拼接
      • 57)MyBatisPlus多条件查询,组合查询
      • 58)前后端交互Long和string
      • 59)覆盖索引,利用覆盖索引进行查询,避免回表
        • 1.什么是回表?
        • 2.回表怎么避免=》覆盖索引
        • 3.使用联合索引完成
      • 60)延迟查询(慢sql)
      • 61)数据库设计时可以考虑存json类型的字段
      • 62)局部变量,成员变量,静态变量的区别
      • 63)JWT权限验证
      • 64)SQL对同一字段的正负数分别累计求和(求累计值)
      • 65)循环方法(JDK8并行流 parallelStream)
      • 66)url在线编辑器对比(https://tool.oschina.net/)
      • 67)HttpRequest的使用(发送http请求)
      • 68)项目中回调的意义
      • 69)判断字符串是否是json字符串
      • 70)assert 断言
      • 71)异常java.lang.IllegalStateException: Method has too many Body parameters
      • 72)json的一些用法基于fastJson
      • 73)mybatis模糊查询
      • 74)mybatis中collection标签的使用
      • 75)在设计数据库是需要预留状态(不能一直连下去,中间考虑空格便于补充状态)
      • 76)初识数据库设计注意事项
      • 77)当Jenkins构建报错,注意查看Jenkins日志:
      • 78)long 小数不行,转bigdecimal
      • 79)修改时间格式
      • 80)parallelStream()优化Stream流(开内部线程去跑,效率提高)
      • 81)sql语句:计算一个字段中的不同状态的和
      • 82)string和集合判空尽量使用stringUtil、CollectionUtil
      • 83)类中 的意义(内部类) c o m . x f w . w e l f a r e . o r d e r . r e s p o n s e . O p e r a t i o n A f t e r S a l e s R e s p o n s e 的意义(内部类)com.xfw.welfare.order.response.OperationAfterSalesResponse 的意义(内部类)com.xfw.welfare.order.response.OperationAfterSalesResponseAfterSalesGoods内部类使用$
      • 84)MyBatis中collection标签使用:一对多
      • 85)spring对文件上传有限制,需要在配置文件中添加
      • 86)父子工程引包问题(找不到注入的类)
      • 87)sql数据截断异常
      • 88)前后端在有判断交互中添加判断字段来控制(如isOk=1/0等)
      • 89)判断字符串中的某一个字符截断字符串
      • 90)文件上传。前端多次调接口多个流的方式上传,可以以集合的方式传,返回多个
      • 91)操作性代码给前端返回boolean
      • 92)多表操作加一定要加事务
      • 93)当上传文件时为了避免错误注意的点
      • 94)sql查询最大的值(函数:查询最新时间也行)
      • 95)mybatis循环插入集合
      • 96)mybatis映射返回类注意点
      • 97)sql分组取出最大值
      • 98)@JsonFormat注解统一返回类时间格式
      • 99)java指定时间
      • 100)封装请求体参数
      • 101)Controller层获取请求 头
      • 102)logback.xml配置
      • 103)application.yml与bootstrap.yml的区别
        • 加载顺序
        • 配置区别
        • 属性覆盖问题
        • bootstrap.yml典型的应用场景
      • 104)判断时间交集
        • 场景
        • 思想是:
      • 105)设置具体时间
      • 106)classpath和classpath*的区别
      • 107)ateway网关转发配置
      • 108)zuul区别
      • 109)get请求传时间,配置时间格式
      • 110)springboot中使用junit测试
      • 111)SSH整合时出现java.lang.IllegalStateException: @Resource annotation requires a single-arg method: ..的错误解决
      • 112)注意int的长度,当生成的id时,int和long之间的精度问题
      • 113)当代码出现问题时一定要有微观到宏观
      • 114)@JsonFormat和@DataTimeFormat的区别
      • 115)所有的查询都要进行判空校验
      • 116)包装类的判断是否,相等使用equals
      • 117)尽量不要在循环中调用数据库连接去查询修改等,原因数据库连接有限,资源宝贵,解决方法:
      • 118)mybatis一对多和多对多的写法和理解
          • 1】编写返回类
          • 2】编写mapper.xml 要点:封装resultMap
          • 总结:写法重点在于书写resultMap
      • 119)简单的覆写的方法
      • 【推荐】在所有的查询语句中都加上排序 order by


java开发小白杂项总结

前言:本人毕业于2021年,刚刚接触java开发,在开发过程中发现自己什么都不懂,因此写下本文作为总结自己在初入开发时遇到的问题,希望有机会看到本文的家人们,避免踩我相同的坑(有些坑自己都觉得傻,本文等于小白成长日志)。本文包括一些java写法,规范,报错问题,常见问题等杂项,希望能帮助各位和我一样刚步入java开发的小伙伴。文中有什么不对的,也希望大家不吝指点。这也是我第一次尝试写博文,一些排版等问题日后也会向大家多多学习。星光不问赶路人 时光不负有心人(本文持续更新)

一、java

1.java8新特性

(1)stream流式操作

在这里插入图片描述

  //使用流过滤
  public static void main(String[] args) { 
    List<String> list = new ArrayList<>();
    list.add("张无忌");
    list.add("周芷若");
    list.add("赵敏");
    list.add("张强");
    list.add("张三丰");
    list.stream().filter(s->s.startsWith("张")).filter(s-> s.length() == 3).forEach(System.out::println);
    
  //流map 
  
      //1.将流中的元素映射到另一个流中,这个是在后期经常用到的,比如方法所接收的返回值是A,但是接收的却是B
    list.stream().map(item -> {
                    ProductInfoAttributes productInfoAttributes = new ProductInfoAttributes();
                    BeanUtils.copyProperties(item, productInfoAttributes);
                    productInfoAttributes.setProductId(productId);
                    productInfoAttributes.setAttributeId(IDGenerator.getId());
                    return productInfoAttributes;
                }).collect(Collectors.toList());
   
      //2.将String类型的流转换为Integer 类型
              Stream<String> stringStream = Stream.of("1", "2", "3", "4", "5", "6");
        stringStream.map(str->Integer.parseInt(str)).forEach(System.out::println);
	
      //3.方法需要返回的是List ,但是这里只有List,此时就要想到stream().map
          public  List<String> queryNamesByIds(List<Long> ids){
        
              List<Category> categories = this.categoryMapper.selectByIdList(ids);
       
    return  categories.stream().map(category -> 					            
                                    category.getName()).collect(Collectors.toList());
    }

2.static使用(与属性注入的关系)

(1)static(主函数是static修饰)只能调用调用static方法

静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。

public abstract class A {
    public static void func1(){
    }
    // public abstract static void func2();  // Illegal combination of modifiers: 'abstract' and 'static'
}

只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字,因为这两个关键字与具体对象关联。

public class A {

    private static int x;
    private int y;

    public static void func1(){
        int a = x;
        // int b = y;  // Non-static field 'y' cannot be referenced from a static context
        // int b = this.y;     // 'A.this' cannot be referenced from a static context
    }
}
(2) 静态内部类(从类的加载顺序可知【加载原则先静态后非静态,先父类再子类】)

非静态内部类依赖于外部类的实例,也就是说需要先创建外部类实例,才能用这个实例去创建非静态内部类。而静态内部类不需要。

public class OuterClass {

    class InnerClass {
    }

    static class StaticInnerClass {
    }

    public static void main(String[] args) {
        // InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
        OuterClass outerClass = new OuterClass();
        InnerClass innerClass = outerClass.new InnerClass();
        StaticInnerClass staticInnerClass = new StaticInnerClass();
    }
}

静态内部类不能访问外部类的非静态的变量和方法。不应该通过类实例访问静态成员,使用类名去访问

  • 父类(静态变量、静态语句块)

  • 子类(静态变量、静态语句块)

  • 父类(实例变量、普通语句块)

  • 父类(构造函数)

  • 子类(实例变量、普通语句块)

  • 子类(构造函数)

3.集合

(1)List中add和addAll的区别

add是添加list对象,addAll是添加list中的每一个object
java开发杂项总结_第1张图片
java开发杂项总结_第2张图片

4.java常用API(常看api文档)

JDK1.8源码中文说明

http://blog.fondme.cn/apidoc/jdk-1.8-google

1.集合(工具类)
 ArrayList<JSONObject> result = Lists.newArrayList();
        List<LfCategory> list = lfCommodityInfoPlMapper.findTypeList(LfType.VIDEO);
        list.addAll(lfCommodityInfoPlMapper.findTypeList(LfType.GAME));


lists.newarraylist()List<String> list = new ArrayList<String>(); 

new arraylist()List<String> list = Lists.newArrayList();

//Lists和Maps是两个工具类, Lists.newArrayList()其实和new ArrayList()几乎一模一样, 唯一它帮你做的(其实是javac帮你做的), 就是自动推导(不是"倒")尖括号里的数据类型.
2.Arrays
//转string 
Arrays.toString
3.Collections
//判断是否为空
Collections.isEmpty

5.IO流

(1)读文件(输入流):

BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("infilename")));

不管你从磁盘读,从网络读,或者从键盘读,读到内存,就是InputStream。

(2)写文件(输出流):

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("outfilename")));

不管你写倒磁盘,写到网络,或者写到屏幕,都是OuputStream

6.java自带util

//CollectionUtils,集合工具类  https://blog.csdn.net/huangwenyi1010/article/details/53706297
//交并补差,是否相等,是否为空等等
CollectionUtils.isEmpty(childCategoryList);

//StringUtils,字符工具类
StringUtils.isEmpty();

二、Mysql

1)外连接查询/函数运用到相应的列


2)模糊查询写法

name like concat(‘%’,#{name},‘%’);

3)foreach/trim区别

//循环数组,开闭,分隔器

        #{id}

/**
trim(剪切的用法)

prefix:在trim标签内sql语句加上前缀。
suffix: 在trim标签内sql语句加上后缀。
suffixOverrides:指定去除多余的后缀内容,如:suffixOverrides=",",去除trim标签内sql语句多余的后缀","。
prefixOverrides: 指定去除多余的前缀内容
**/


        insert into lf_commodity_info
        
            code,
            name,
            value_str,
            type_code,
            member_type,
            price,

            category,

            underlined_price,
            selling_price,

            type,
            enable,
            created,
            updated,
            tax_rate,
        
        
            #{code},
            #{name},
            #{valueStr},
            #{typeCode},
            #{memberType},
            #{price},

            #{category},

            #{underlinedPrice},
            #{sellingPrice},

            #{type},
            #{enable},
            #{created},
            #{updated},
            #{taxRate},
        
    

4)Mybatis插入list集合

 insert into lf_commodity_info(
            id,
            code,
            name,
            value_str,
            type_code,
            member_type,
            category,
            price,
            underlined_price,
            selling_price,
            type,
            enable,
            tax_rate,
            created,
            updated)
            values
            <foreach collection="list" index="index" item="item" separator=",">
                (
                 #{item.id},
                 #{item.code},
                 #{item.name},
                 #{item.valueStr},
                 #{item.typeCode},
                 #{item.memberType},
                 #{item.category},
                 #{item.price},
                 #{item.underlinedPrice},
                 #{item.sellingPrice},
                 #{item.type},
                 #{item.enable},
                 #{item.taxRate},
                 #{item.created},
                 #{item.updated}
                )
            </foreach>
 //sql语句   
INSERT INTO student(name,age,sex)
VALUES("张三",12,"男"),("王三",12,"男")

5)关联查询

select icon
        from lf_category a
        right join lf_commodity_info b on a.type=b.type
        where b.category = #{category}
5.1.sql左联右联的差别

​ 左联接:已一边为主表保留其全部数据

6)嵌套查询

select icon
        from lf_category a
        where a.type = (select type
                        from lf_commodity_info b
                        where b.category = #{category})

7)distinct关键字去重

//distinct去重查询
select icon
        from lf_category a
        where a.type = (select DISTINCT type from lf_commodity_info b where b.category = #{category})
    
    
 //关联查询的去重   
    SELECT
	a.id,
	a.title,
	a.total,
	count( DISTINCT ( b.user_id ) ) AS 'read',//去重后计算该类别中的总数
	a.time,
	a.status 
FROM
	message a
	RIGHT JOIN msg_read b ON a.id = b.msg_id
	GROUP BY a.id//巧用分组,分组计算

三、Spring全家桶

1.注解

(1)Spring中异步注解@Async的使用、原理及使用时可能导致的问题

(2)

  1. @requestBody(将json转成object对象,前端到后端交互时使用)

    注解@RequestBody接收的参数是来自requestBody中,即请求体。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。

	  @RequestParam():@RequestParam

注解@RequestParam接收的参数是来自HTTP请求体或请求url的QueryString中。

RequestParam可以接受简单类型的属性,也可以接受对象类型。

@RequestParam有三个配置参数:

required 表示是否必须,默认为 true,必须。
defaultValue 可设置请求参数的默认值。
value 为接收url的参数名(相当于key值)

(3)@PathVariable(接收类如aaa/{id})直接在url后的参数

(4)@Cacheable(用于缓存注解)

​ @Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。

(5)@Configration

​ @ConfigrationProperties(prefix=“lf”) //配置类的注解

(6)@RequestMapping请求和别的区别

  @RequestMapping(name = " 支付宝 支付返回数据", value = "/aliPay/return_url", method = {RequestMethod.POST, RequestMethod.GET})

2.OpenFeign的使用

创建应用主类Application,并通过@EnableFeignClients注解开启Spring Cloud Feign的支持功能。

@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients(basePackages = { "com.kyle.client.feign.inter" })
public class Application {
    
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

▪️定义HelloServiceFeign,接口@FeignClient注解指定服务名来绑定服务,然后再使用Spring MVC的注解来绑定具体该服务提供的REST接口。

@FeignClient(value = "hello-service-provider")
public interface HelloServiceFeign {

    @RequestMapping(value = "/demo/getHost", method = RequestMethod.GET)
    public String getHost(String name);

    @RequestMapping(value = "/demo/postPerson", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
    public Person postPerson(String name);
}

注意:这里服务名不区分大小写,所以使用hello-service-provider和HELLO-SERVICE-PROVIDER都是可以的。另外,在Brixton.SR5版本中,原有的serviceId属性已经被废弃,若要写属性名,可以使用name或value。

▪️接着,创建一个RestClientController来实现对Feign客户端的调用。使用@Autowired直接注入上面定义的HelloServiceFeign实例,并在postPerson函数中调用这个绑定了hello-service服务接口的客户端来向该服务发起/hello接口的调用。

@RestController
public class RestClientController {
@Autowired
private HelloServiceFeign client;

/**
 * @param name
 * @return Person
 * @Description: 测试服务提供者post接口
 * @create date 2018年5月19日上午9:44:08
 */
@RequestMapping(value = "/client/postPerson", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
public Person postPerson(String name) {
    return client.postPerson(name);
}

/**
 * @param name
 * @return String
 * @Description: 测试服务提供者get接口
 * @create date 2018年5月19日上午9:46:34
 */
@RequestMapping(value = "/client/getHost", method = RequestMethod.GET)
public String getHost(String name) {
    return client.getHost(name);

MyDev
java开发杂项总结_第3张图片

//添加注解,实现api接口
@RestController
public class IfClient implements LfHandleApi {
    @Resource
    private LfCommodityInfoMapper lfCommodityInfoMapper;
    @Resource
    private DocLfPayService lfPayService;
    @Resource
    private LfCategoryMapper lfCategoryMapper;

    /***
     *在璐付平台进行支付
     * @param lfOrderInfo
     * @author xusj
     * 
CreateDate 2022/1/4 10:06 */
@Override public void pay(LfOrderInfo lfOrderInfo) { //查找商品 LfCommodityInfo commodityInfo = lfCommodityInfoMapper.findByCode(lfOrderInfo.getCode()); if (commodityInfo == null) { throw new BizException(ErrorMessages.BASIC_0001, "商品不存在"); } switch (commodityInfo.getType()) { case LfType.VIDEO: lfPayService.payVideo(commodityInfo, lfOrderInfo.getAccount(), lfOrderInfo.getOrderNo()); break; case LfType.GAME: case LfType.RECHARGE_CARD: lfPayService.payGame(commodityInfo, lfOrderInfo.getAccount(), lfOrderInfo.getIp(), lfOrderInfo.getOrderNo()); break; case LfType.PHONE_BILL: lfPayService.payMobile(commodityInfo, lfOrderInfo.getAccount(), lfOrderInfo.getOrderNo()); break; default: throw new BizException(ErrorMessages.BASIC_0001, "商品类型不存在!"); } } @Override public LfCommodityInfo findByCode(String code) { //通过code查询 LfCommodityInfo lfCommodityInfo = lfCommodityInfoMapper.findByCode(code); return lfCommodityInfo; } @Override public String getIcon(Long category) { return lfCategoryMapper.selectIcon(category); }
@EnableFeignClients//远程调用入口
@SpringBootApplication
@MapperScan(value = "com.xfw.welfare.docking.lf.mapper")
public class DockingApplication {

    public static void main(String[] args) {
        SpringApplication.run(DockingApplication.class, args);
    }

}
//api模块,去调用别的模块,定义api接口
@FeignClient(value = "${lf.namespace:}lf")
public interface LfHandleApi {
    /**
     * description: 调用璐付支付接口
     *
     * @param lfOrderInfo 璐付订单信息
     * @author xieran
     * @date 2021/12/29 14:18
     */
    @GetMapping("/api/welfare-lf/pay")
    void pay(@RequestBody LfOrderInfo lfOrderInfo);
    /**
     * description:获取lf商品
     *
     * @param code code
     * @return com.xfw.welfare.docking.lf.domain.LfCommodityInfo
     * @author xr
     * @date 2022/1/4 9:56 上午
     */
    @GetMapping("/api/welfare-lf/findByCode")
    LfCommodityInfo findByCode(String code);
    /**
     * description:查询产品icon
     *
     * @param category 类别id
     * @return java.lang.String
     * @author xr
     * @date 2022/1/4 4:45 下午
     */
    @GetMapping("/api/welfare-lf/getIcon")
    String getIcon(@RequestParam("category") Long category);
}
理解feign的代码架构方式

三层架构的理解,lfclient,DocLfPayservice,DocLfPayserviceimpl 区别

一、远程调用类再主服务中,实现api中api接口方法(这里写url),需要注解@RestController,类似于实现类

3.@Scheduled定时任务cron表达式

定时任务Scheduled

cron表达式详解https://help.eset.com/era_admin/65/zh-CN/cron_expression.html

@Component
public class Task
{
    @Scheduled(cron="0/5 * *  * * ? ")   //每5秒执行一次
    public void execute(){
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置日期格式
        System.out.println("欢迎访问 pan_junbiao的博客 " + df.format(new Date()));
    }


//启动类添加注解
@SpringBootApplication
@EnableScheduling //开启定时任务
public class ScheduledDemoApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(ScheduledDemoApplication.class, args);
    }


4.配置文件的使用

server: //端口
  port: ${APP_PORT:19970}

spring:
  application:
    name: ${order-server.namespace:}order
  cloud:
    nacos:
      username: ${NACOS_SERVER_USERNAME:nacos}
      password: ${NACOS_SERVER_PASSWORD:xfw1234}
      server-addr: ${NACOS_SERVER_ADDR:172.16.9.159:8848}
      config: //nacos中配置的前缀和yml后缀
        prefix: order
        enabled: true
        file-extension: yml
      discovery:
        enabled: true

  profiles:
    active: @profiles.active@
  main:
    allow-bean-definition-overriding: true

四、Mybatis

1、传参问题

1.MyBatis BindingException: Parameter ‘a’ not found(mapper中的参数没有在xml里被使用)

2.解决
java开发杂项总结_第4张图片
java开发杂项总结_第5张图片

这里需要注意的是collection必须为array,否则会报错如下:

Caused by: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [array]
<select id="selectList" parameterType="java.util.List" resultType="java.lang.Integer">
        SELECT COUNT(1) FROM t_user
        WHERE id IN
        <foreach collection="array" index="index" item="item"
            open="(" separator="," close=")">
            #{item}
        </foreach>
    </select>

复制代码

2、result问题

MyBatis.TooManyResultsException(封装的返回值不够)

3、异常

java.sql.SQLIntegrityConstraintViolationException(违反完整性约束):
一、其实就是违反了数据库的唯一约束条件!也就是插入数据时,具有唯一约束条件的列值重复了。
根据我图中描述信息的展示可知,我的表中"test1"这一列是具有唯一约束的,现在插入列值时数据有重复了。所以务必确认插入数据的主键或者具有唯一性约束的列不要有重复数据!!!

二、缺少主键

4.sql片段的使用

//标签和标签的使用
<sql id="selectLfCommodityInfoVo">
        select id,
               code,
               name,
               value_str,
               type_code,
               member_type,
               category,
               price,
               underlined_price,
               selling_price,
               type,
               enable,
               tax_rate,
               created,
               updated
        from lf_commodity_info
    </sql>
    <select id="findByCode" resultType="com.xfw.welfare.docking.lf.domain.LfCommodityInfo">
        <include refid="selectLfCommodityInfoVo"></include>
        where code=#{code}
    </select>

5、trim剪切标签的使用

//
 <insert id="insertLfCommodityInfo" parameterType="vip.forwe.model.lf.LfCommodityInfoModel" useGeneratedKeys="true"
            keyProperty="id">
        insert into lf_commodity_info
        <trim prefix="(" suffix=")" suffixOverrides=",">//suffixOverrides后缀覆盖
            <if test="code != null">code,</if>
            <if test="name != null">name,</if>
            <if test="valueStr != null">value_str,</if>
            <if test="typeCode != null">type_code,</if>
            <if test="memberType != null">member_type,</if>
            <if test="price != null">price,</if>

            <if test="category != null">category,</if>

            <if test="underlinedPrice != null">underlined_price,</if>
            <if test="sellingPrice != null">selling_price,</if>

            <if test="type != null">type,</if>
            <if test="enable != null">enable,</if>
            <if test="created != null">created,</if>
            <if test="updated != null">updated,</if>
            <if test="taxRate != null">tax_rate,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="code != null">#{code},</if>
            <if test="name != null">#{name},</if>
            <if test="valueStr != null">#{valueStr},</if>
            <if test="typeCode != null">#{typeCode},</if>
            <if test="memberType != null">#{memberType},</if>
            <if test="price != null">#{price},</if>

            <if test="category != null">#{category},</if>

            <if test="underlinedPrice != null">#{underlinedPrice},</if>
            <if test="sellingPrice != null">#{sellingPrice},</if>

            <if test="type != null">#{type},</if>
            <if test="enable != null">#{enable},</if>
            <if test="created != null">#{created},</if>
            <if test="updated != null">#{updated},</if>
            <if test="taxRate != null">#{taxRate},</if>
        </trim>
    </insert>
    
                //separator分隔符
                
                <foreach collection="list" index="index" item="item" separator=",">
                (
                 #{item.id},
                 #{item.code},
                 #{item.name},
                 #{item.valueStr},
                 #{item.typeCode},
                 #{item.memberType},
                 #{item.category},
                 #{item.price},
                 #{item.underlinedPrice},
                 #{item.sellingPrice},
                 #{item.type},
                 #{item.enable},
                 #{item.taxRate},
                 #{item.created},
                 #{item.updated}
                )
            </foreach>

五、异常总结

1)数据截断异常

数据截断异常:(原因:导入的数据长度大于数据库长度)

Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation

2)BadSqlGrammarException(只要报这个异常,直接将语句放到数据库调试)

​ sql语句的问题,1.列名,2.sql语句的异常1.sql列数和参数不一样多

3)result问题

MyBatis.TooManyResultsException(封装的返回值不够)

4)异常

java.sql.SQLIntegrityConstraintViolationException(违反完整性约束):
一、其实就是违反了数据库的唯一约束条件!也就是插入数据时,具有唯一约束条件的列值重复了。
根据我图中描述信息的展示可知,我的表中"test1"这一列是具有唯一约束的,现在插入列值时数据有重复了。所以务必确认插入数据的主键或者具有唯一性约束的列不要有重复数据!!!

二、缺少主键

5)java.lang.IllegalArgumentException: Pattern cannot be null or empty

个人经验,该传的参数没传,参数名称写错了,@requestBody/@requestParam 忘记注解

其他具体问题参考:https://blog.csdn.net/weixin_44259720/article/details/103185972

6)feign.FeignException$NotFound: [404] during [POST]

feign调用失败,当代码确定没用问题的前提下,可能时分布式架构下,多服务启动造成的问题,解决方法在调用方服务中添加被调用方服务名
java开发杂项总结_第6张图片

六、第三方开发工具的使用

1.xshell的使用(linux常用命令行)

https://www.cnblogs.com/bowendown/p/11937159.html 下载安装地址

开发常用命令

tail -200f welfare-operation.nohup.out ()查看具体文件的后几行,查看部署环境下最后发生了什么问题

cd 进入文件

2.xxlJob分布式定时任务的使用

官方文档:https://www.xuxueli.com/xxl-job/

项目结构:
java开发杂项总结_第7张图片

快速入门:

1.建两个分布式事务模块

2.建数据库

3.导入依赖

4.xxlJob配置类(可将配置写入nocas等),必写不然通过代码是不能注册任务的

package com.xfw.welfare.message.config;

import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * xxl-job配置
 * @author xieran
 */
@Configuration
@Slf4j
public class XxlJobConfig {
    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.accessToken}")
    private String accessToken;

    @Value("${xxl.job.executor.appname}")
    private String appname;

    @Value("${xxl.job.executor.address}")
    private String address;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @Value("${xxl.job.executor.port}")
    private int port;

    @Value("${xxl.job.executor.logpath}")
    private String logPath;

    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;

	//执行器组件
    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        log.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);

        return xxlJobSpringExecutor;
    }


}

5.添加并启动任务为例(其实就是调用xxljob的接口)

/***
     *请求xxl-job创建并启动任务接口
     *
     * @param xxlJobInfo 任务参数  如果 xxlJobInfo.getTriggerStatus == 1 创建的同时并启动任务,xxlJobInfo.getTriggerStatus == 0 只创建任务
     * @return {@link Integer}
     * @author xusj
     * 
CreateDate 2022/1/21 10:59 */
//1.XxlJobInfo此参数其实理解上来就是数据库中的XxlJobInfo实体类,实体类见下方 //2.调用addAndStart见下 public Integer addAndStart(XxlJobInfo xxlJobInfo) { //发送请求,到xxljobAdmin微服务的controller接口,详细结构见截图 HttpsRequest request = new HttpsRequest(addAndStartUrl + "/jobinfo/addAndStart"); // 任务参数 request.setJsonBody(JSONObject.toJSONString(xxlJobInfo)); if (request.executePostRequest()) { String response = request.getResponse(); log.info("创建任务:response==={}", response); JSONObject jo = JSON.parseObject(response); if (!"200".equals(jo.getString("code"))) { log.error("创建启动任务失败,jobId={}", xxlJobInfo.getId()); throw new RuntimeException(jo.getString("msg")); // throw new BusinessException(jo.getString("msg")); } return jo.getInteger("content"); } throw new RuntimeException("创建任务失败"); // throw new BusinessException("创建任务失败"); }

6.实体类(对标数据库中的xxljobinfo表)

package com.xfw.welfare.message.xxljob;

import lombok.Data;

import java.util.Date;

/**
 * @author xusj
 * 
CreateDate 2022/1/21 0:30 */
@Data public class XxlJobInfo { private int id; // 主键ID private int jobGroup; // 执行器主键ID private String jobDesc; private Date addTime; private Date updateTime; private String author; // 负责人 private String alarmEmail; // 报警邮件 private String scheduleType; // 调度类型 private String scheduleConf; // 调度配置,值含义取决于调度类型 private String misfireStrategy; // 调度过期策略 private String executorRouteStrategy; // 执行器路由策略 private String executorHandler; // 执行器,任务Handler名称 private String executorParam; // 执行器,任务参数 private String executorBlockStrategy; // 阻塞处理策略 private int executorTimeout; // 任务执行超时时间,单位秒 private int executorFailRetryCount; // 失败重试次数 private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum private String glueSource; // GLUE源代码 private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 private String childJobId; // 子任务ID,多个逗号分隔 private int triggerStatus; // 调度状态:0-停止,1-运行 private long triggerLastTime; // 上次调度时间 private long triggerNextTime; // 下次调度时间 private String appName; // 执行器名称 }

7.调用上方5api

		//创建并启动任务
        XxlJobInfo xxlJobInfo = assemblyParam(msgDetRequest);
		//添加并启用
        Integer jobId = addAndStartApi.addAndStart(xxlJobInfo);


/***
     * 封装构建job任务参数方法
     *
     * @param msgDetRequest 消息请求详情
     * @return {@link XxlJobInfo}
     * @author xusj
     * 
CreateDate 2022/1/21 10:17 */
public XxlJobInfo assemblyParam(MsgDetRequest msgDetRequest) { //将时间转化为cron表达式 String cron = DateUtil.getCron(msgDetRequest.getDate()); //生成jobId Long jobId = IDGenerator.getId(); // jobGroup必须为 ( jobGroup必须为代表的是对应执行器,如果执行器不知道是多少就默认为 0,但是必须传执行器名称appName) XxlJobInfo xxlJobInfo = new XxlJobInfo(); xxlJobInfo.setId(jobId.intValue()); xxlJobInfo.setJobGroup(0); xxlJobInfo.setAppName("message-executor"); xxlJobInfo.setJobDesc("定时推送消息任务" + msgDetRequest.getTitle()); xxlJobInfo.setAddTime(new Date()); xxlJobInfo.setUpdateTime(new Date()); xxlJobInfo.setAuthor("admin"); xxlJobInfo.setScheduleType("CRON"); xxlJobInfo.setScheduleConf(cron); xxlJobInfo.setMisfireStrategy("DO_NOTHING"); xxlJobInfo.setExecutorRouteStrategy("FIRST"); //TODO 设置jobHandler名称 xxlJobInfo.setExecutorHandler("messageHandler"); //TODO 任务参数 消息id xxlJobInfo.setExecutorParam(String.valueOf(msgDetRequest.getMsgId())); xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION"); xxlJobInfo.setExecutorTimeout(0); xxlJobInfo.setExecutorFailRetryCount(3); xxlJobInfo.setGlueType("BEAN"); xxlJobInfo.setGlueRemark("GLUE代码初始化"); xxlJobInfo.setGlueUpdatetime(new Date()); //TODO 调度状态:0-停止,1-运行 刚添加的调度状态为0(添加定时任务默认为开启) xxlJobInfo.setTriggerStatus(1); xxlJobInfo.setTriggerLastTime(0L); xxlJobInfo.setTriggerNextTime(0L); return xxlJobInfo; }

3.redis使用

https://www.cnblogs.com/yechangzhong-826217795/p/11202316.html

使用安装redis 的坑

Can’t connect to redis-server

解决 运行=》services.msc=》redis启用

4.Jrebel热部署(提高开发效率)

https://www.haah.net/archives/6285.html

七、中间件的使用

1.nacos官方文档

springCloud 引入nocas官方文档 https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

1.下载,

2.导入两个依赖

3.yml书写

server:
  port: ${APP_PORT:19977}

spring:
  application:
    name: ${message.namespace:}message
  cloud:
  #重点:寻找nocas中的配置文件
    nacos:
      username: ${NACOS_SERVER_USERNAME:nacos}
      password: ${NACOS_SERVER_PASSWORD:666}
      server-addr: ${NACOS_SERVER_ADDR:172.16.9.149:666}
      config:
        prefix: message
        enabled: true
        file-extension: yml
      discovery:
        enabled: true

  profiles:
    active: dev
  main:
    allow-bean-definition-overriding: true

八、开发中Problem

1)spring中使用Junit测试

1、导入Junit依赖

​ 2、注意测试类的路径必需与非测试类路径一样

可参考:https://blog.csdn.net/weixin_39800144/article/details/79241620

注解

@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderTest {
    @Resource
    private OrderPremiumServiceImpl orderPremiumService;
    @Resource
    private BaseInfoMapper baseInfoMapper;
    @Resource
    private BaseProductItemsMapper productItemsMapper;

//    @Test
//    public void testCreateOrder(){
//        CreatOrderRequest request = new CreatOrderRequest();
//
//        orderPremiumService.createOrder()
//    }

    /**
     * 测试,订单信息入库 √
     */
    @Test
    public void testSave() {
        BaseInfo baseInfo = new BaseInfo();
        baseInfo.setBaseInfoId(Long.valueOf(10));
        BaseInfoBuyerContact baseInfoBuyerContact = new BaseInfoBuyerContact();
        baseInfoBuyerContact.setBuyerId(Long.valueOf(20));
        BaseInfoSellerContact baseInfoSellerContact = new BaseInfoSellerContact();
        baseInfoSellerContact.setSellerId(Long.valueOf(30));
        BaseInfoReceInfo baseInfoReceInfo = new BaseInfoReceInfo();
        baseInfoReceInfo.setReceInfoId(Long.valueOf(50));

        BaseInfoLogistics baseInfoLogistics = new BaseInfoLogistics();
        baseInfoLogistics.setLogId(Long.valueOf(60));

        BaseInfoLogisticsItems baseInfoLogisticsItems = new BaseInfoLogisticsItems();
        baseInfoLogisticsItems.setLogItemsId(Long.valueOf(70));

        BaseProductItems baseProductItems = new BaseProductItems();
        baseProductItems.setId(Long.valueOf(80));
//        orderPremiumService.saveOrder(baseInfo, baseInfoBuyerContact, baseInfoSellerContact, baseInfoReceInfo,
//                baseInfoLogistics, baseInfoLogisticsItems, baseProductItems);
    }

2)代码规范

分new ,get,set(分点组装从参数)

总new ,get,set(将分点组装进总参数)

类中定义方法,代码冗余,地区定义

// 2. 拼接省市区镇街道,调用1688api解析地址编码,调用内部类,并调用内部类中的方法(方法定义在类中)
String districtCode = getDistrictCode(request.getDeliveryAddress().getAddressText());
/** * 地址拼接 * * @return */字符串拼接,使用stringBuilder
public String getAddressText() {    
    StringBuilder text = new StringBuilder();    	text.append(provinceText).append(cityText).append(areaText).append(townText).append(address);    
    return text.toString();}

3)分装json对象

//jsonObject 返回json对象(如何封装json对象)
public ArrayList<JSONObject> phoneBill() {
        ArrayList<JSONObject> result = Lists.newArrayList();
        List<LfCategory> list = lfCommodityInfoPlMapper.findTypeList(LfType.PHONE_BILL);
        list.forEach(LfCategory -> {
            JSONObject category = new JSONObject();
            category.putOpt("id", LfCategory.getId());
            category.putOpt("name", LfCategory.getName());
            category.putOpt("icon", LfCategory.getIcon());
            category.putOpt("rule", LfCategory.getRules());
            category.putOpt("specifications", lfCommodityInfoPlMapper.findCommodityListByCategoryId(LfCategory.getId()));
            int dayOfMonth = DateUtil.thisDayOfMonth();
            //每月的8-19号 有优惠 其他日期原价
            category.putOpt("discount", dayOfMonth >= Constant.PHONE_BILL_DISCOUNT_START && dayOfMonth <= Constant.PHONE_BILL_DISCOUNT_END);
            result.add(category);
        });
        return result;
    }

4)发送Http请求/获取httpRequest和httpResponse

//1,hutool 
//发送http请求
HttpResponse response = HttpRequest.post(LFPayGameRequest.URL).form(BeanUtil.beanToMap(request)).timeout(10000).execute();
//2.HttpClient发送

//怎么获得httprequest和httpresponse

public abstract class BaseHandler extends ResponseEntityExceptionHandler {
private static ServletRequestAttributes getRequestAttributes() {
    RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
    return (ServletRequestAttributes) attributes;
}

protected static HttpServletRequest getRequest() {
    return getRequestAttributes().getRequest();
}

protected static HttpServletResponse getResponse() {
    return getRequestAttributes().getResponse();
}

/**
 * 未知异常
 */
@ExceptionHandler(Throwable.class)
@ResponseBody
public Response<?> handleThrowable(Throwable ex) {
    logger.error("BaseHandler Error", ex);
    return Response.error(new BusinessException(ErrorMessages.BASIC_0001));
}
}

5)封装对象,

//lf支付请求参数,封装方法
@Data
public class LFPayGameRequest {
    //定义静态常量
    public static final String URL = "http://open.jiaofei100.com/Api/PayGame.aspx";


    private String APIID;
    private String TradeType;
    private String Account;
    private String UnitPrice;
    private String BuyNum;
    private String TotalPrice;
    private String OrderID;
    private String CreateTime;
    private String isCallBack;
    private String GoodsID;
    private String ClientIP;
    private String Sign;


    /**
     * 生成 sign
     */
    //定义类方法
    public String generateSign(String appKey) {
        String sb = "APIID=" + APIID +
                "&Account=" + Account +
                "&BuyNum=" + BuyNum +
                "&ClientIP=" + ClientIP +
                "&CreateTime=" + CreateTime +
                "&GoodsID=" + GoodsID +
                "&isCallBack=" + isCallBack +
                "&OrderID=" + OrderID +
                "&TotalPrice=" + TotalPrice +
                "&TradeType=" + TradeType +
                "&UnitPrice=" + UnitPrice +
                "&APIKEY=" + appKey;
        return MD5Util.md5Hex(sb).toUpperCase();
    }
}

6)BigDecimal类型转化千万不能强制类型转换(精度丢失,详见阿里开发手册),转化(元,分,厘)【无非就是简单的乘除操作】

//BigDecimal
//单位 厘
        BigDecimal price = infoModel.getUnderlinedPrice().multiply(new BigDecimal("1000")).setScale(0);


BigDecimal 分转元

BigDecimal feeNo = new BigDecimal(fee);//string 转 BigDecimal 分转元
feeNo = feeNo.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);//分转元

7)String 的正则表达式

fileName.matches("^.+\\.(?i)(xlsx)$")//matches方法

8)pom文件引用的坑,用于抽取API模块时,依赖引用问题

主类中应用api即可,api中不能引用主类中的依赖

9)前后端文件传输

https://blog.csdn.net/sdut406/article/details/85647982 MultipartFile与File的一些事,这两个词一般是Java中出现的吧,前者代表HTML中form data方式上传的文件,后者是文件系统的抽象,前者信息较少,只有二进制数据+文件名称

10)枚举类和属性类的区别

属性类

public class LfType {

    /**
     * 类型 :  1.视频  2.游戏 3.话费类 4.卡密
     */
    public final static int VIDEO = 1;
    public final static int GAME = 2;
    public final static int PHONE_BILL = 3;
    public final static int RECHARGE_CARD = 4;


}

枚举类

package com.xfw.common.enums;

import lombok.Getter;

/**
 * @Classname CodeEnum
 * @Date 2021/10/19 4:19 下午
 * @Created by ys
 */
@Getter
public enum CodeResponseEnum {

    PARAMETER_ERROR(10007, "参数错误"),
    ORDER_TIMEOUT(10008, "订单超时"),
    PARAMETER_VERIFICATION_ERROR(10009, "参数校验错误"),
    AGENCY_ID_DOES_NOT_EXIST(10010, "代理商 ID 不存在"),
    NUMBER_TO_LONG(10011, "订单号长度大于 36"),
    AGENCY_STATUS_ERROR(10012, "代理商状态错误"),
    INSUFFICIENT_BALANCE(10013, "账户余额不足"),
    IP_ERROR(10014, "IP 地址验证失败"),
    PHONE_ERROR(10015, "充值号码有误"),
    NOT_SUPPORT(10016, "暂不支持该号码"),
    BAN(10017, "禁止采购该商品"),
    SUCCESS(10018, "订单提交成功"),

    FAILED(10020, "订单提交失败"),
    UNKNOWN(10021, "未知错误"),
    DUPLICATE(10022, "订单号重复"),
    NOT_SUPPORT_01(10024, "暂不支持该面值"),
    PROCESSING(10025, "订单处理中"),
    FAIL_TRANSACTION(10026, "交易失败"),
    SUCCESS_TRANSACTION(10027, "交易成功"),

    NOT_EXIST(10029, "订单不存在"),
    LIMIT(10035, "限制5分钟内同一时间和同一个金额"),
    MAINTENANCE(10036, "系统维护"),
    NOT_STARTED(10037, "活动未开始"),
    FINISH(10038, "活动已经结束"),
    ;

    private final int code;
    private final String msg;

    CodeResponseEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    /**
     * 通过code 获取 enum 对象
     */
    public static CodeResponseEnum getEnum(int code) {
        CodeResponseEnum result = null;
        for (CodeResponseEnum s : values()) {//values 表示当前枚举类
            if (s.getCode() == code) {
                result = s;
                break;
            }
        }
        return result;
    }

}

11)list.foreach的实际应用

 productCategoryList.forEach(categoryDTO -> {
     
            List<ProductCategoryResponse> childCategoryList = productCategoryFactory.getChild(allProductCategoryList,
                    categoryDTO.getId(), getAllCategoryList(), request.getQueryType());
            if(Objects.nonNull(request.getQueryType()) && request.getQueryType() == 1){
                //在商品分类界面调用,需要返回商品
                int productNum = 0;
                if(CollectionUtils.isEmpty(childCategoryList)){
                    List<Long> categoryIds = new ArrayList<>();
                    ProductCategoryRelWrapper.Selecter matcherSumProductList = new ProductCategoryRelWrapper.Selecter();
                    matcherSumProductList.categoryIdIn(categoryIds);
                    productNum = productCategoryRelMapper.selectCount(matcherSumProductList).intValue();
                }else {
                    productNum = childCategoryList.stream().mapToInt(ProductCategoryResponse::getProductNum).sum();
                }
                categoryDTO.setProductNum(productNum);
            }
            categoryDTO.setCategoryChildList(childCategoryList);
        });

12)巧用三元运算符

/**
     * 获取限购商品库存,三元运算符
     */
    public int getInventory(String purchaseLimitCode) {
        String key = getKey(purchaseLimitCode);
        Integer inventory = (Integer) redisTemplate.opsForValue().get(key);
        return inventory == null ? 0 : inventory;
    }

13)Date格式

new DateTime().toString("yyyyMMddHHmmss")//??导入依赖,有问题
    	//java自带
   	    Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        String s = dateFormat.format(date);
        System.out.println(s);

14)excel导入导出

取excel的坑 https://blog.csdn.net/qq_35893120/article/details/80395080

导出excel模板 https://blog.51cto.com/u_15127658/4337321

15)DTO和VO的区别

http://www.tnblog.net/aojiancc2/article/details/2396

前后端交互使用request和response

VO(View Object):封装参数

​ 视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。

DTO(Data Transfer Object):网络传输,中间件的交互

​ 数据传输对象,泛指用于展示层与服务层之间的数据传输对象。

PO(Persistent Object):

​ 持久化对象,就是和数据库保持一致的对象

16)开发工具安装问题,程序扫描

安装目录空格,查看报错信息,%(符号为百分号),将workspace拉到别的地方

17)配置文件

绑定异常(修改配置文件),我们使用的时Mybatis-plus,实际我们的配置为mybatis,所以配置类读取错误

mybatis-plus:

​ type-aliases-package: com.xfw.welfare.docking

​ mapper-locations: classpath* */mapper/mapping/ *.xml

18)接不到参数为空,原因

接前端参数,或者接远程调用的参数的为null时可能时因为@RequestBody注解忘记打了等注解没使用

19)为了再nacos中起不一样的服务,避免开发冲突(其中在调用方也需要配置调用方)

//不然可以会报找不到服务
java开发杂项总结_第8张图片

20)数据库设计,时间自动增长,和插入的时间有关

java开发杂项总结_第9张图片
阿里java

21)转化请求的时间格式

转时间格式(在类属性中)

  @ApiModelProperty(value = "操作时间,最近一次上下架的时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date operateDate;

22)在类中使用静态变量(定义常量)和方法(日常写法)

package com.xfw.welfare.docking.dto.request;

import cn.modousa.mds.common.tools.MD5Util;
import lombok.Data;

/**
 * @author xusj
 * 
CreateDate 2022/1/4 10:46 */
@Data public class LFPayVideoRequest { public static final String URL = "http://open.jiaofei100.com/Api/PayVideo.aspx"; private String APIID; private String Account; private String ProductCode; private String BuyNum; private String OrderID; private String CreateTime; private String IsCallBack; private String CallBack; private String Sign; /** * 生成 sign */ public String generateSign(String appKey) { String sb = "APIID=" + APIID + "&Account=" + Account + "&BuyNum=" + BuyNum + "&CreateTime=" + CreateTime + "&IsCallBack=" + IsCallBack + "&OrderID=" + OrderID + "&ProductCode=" + ProductCode + "&APIKEY=" + appKey; return MD5Util.md5Hex(sb).toUpperCase(); } }

23)private和public修饰属性的区别

private String a;//需要set get方法,new之后get出来

public String b;//可以new之后直接点出来

24)数据库和mq的了解

1.数据库设计 https://github.com/jly8866/archer/blob/master/src/docs/mysql_db_design_guide.md

2.了解mq的使用场景 https://www.zhihu.com/question/34243607

25)MultipartFile文件流,前后端交互

// MultipartFile转inputstream,前后端传文件流,不会传地址,传的是文件流
//例
@PostMapping("/upload")
    @ApiOperation("上传文件到oss")
    @ApiImplicitParam(name = "pathName", value = "参数,文件地址", required = true, dataType = "MultipartFile")
    public Response<String> uploadFile(@RequestParam MultipartFile pathName) throws IOException {
        String filename = pathName.getOriginalFilename();//获得流中的文件名
        InputStream inputStream = pathName.getInputStream();//将文件流转化为输入流
        String url = ossUtil.uploadFile(inputStream,filename);//调用下面的方法
        if (!StringUtils.isEmpty(url)) {
            return Response.ok(url);
        }
        log.error("文件上传到Oss失败");
        throw new BusinessException(ErrorMessages.BASIC_0001);
    }


//oss通过流上传文件
 public String uploadFile(InputStream inputStream,String fileName) throws IOException {

        //首先判断是否有welfare的存储空间
        createBucket();

        //将本地文件上传到存储空间bucket中的目录中
        //依次填写Bucket名称(例如examplebucket)、Object完整路径(例如exampledir/exampleobject.txt)和本地文件的完整路径。Object完整路径中不能包含Bucket名称。
        //TODO bucket下的目录文件夹?
        PutObjectRequest objectRequest = new PutObjectRequest(OssConfig.BUCKET_NAME, "common/" + fileName,inputStream);
        //上传文件
        PutObjectResult putObjectResult = ossClient.putObject(objectRequest);
        //判断ETag(ETag用于标识一个Object的内容)
        if (StringUtils.isEmpty(putObjectResult.getETag())) {
            log.error("上传文件失败{}");
            //关闭OssClient
            ossClient.shutdown();
            return "false";
        }
        log.info("上传文件成功{}");
        //拼接访问url
        String url = backUrl(fileName);
        //关闭OssClient
        ossClient.shutdown();
        return url;
    }



//示例,多态,没必要强行给fileinputstream,想的不全面,变通一点,在idea中查看java继承体系,ctrl+h
右键,最后一个,show继承体系
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
//多态
InputStream inputStream = new FileInputStream("D:\\localpath\\examplefile.txt");

26)jenkens部署,发送代码时,记得发布到测试环境

27)使用mybatisplus Wrapper层的作用

除了关联查询不行,基本上都可以操作

 @Override
    public AlipayOrderInfo findByOutTradeNo(String outTradeNo) {
        AlipayOrderInfoWrapper.Selecter matcher = new AlipayOrderInfoWrapper.Selecter();
        //通过以上对象进行具体的操作
        matcher.outTradeNoEq(outTradeNo);//等于
        matcher.orderByDesc(AlipayOrderInfo.cols().id().orderNo().toList());//降序
        
        return alipayOrderInfoMapper.selectOne(matcher);//wrapper入参
    }


  @Override
    public AlipayOrderInfo findByOrderNo(String orderId) {
        AlipayOrderInfoWrapper.Selecter matcher = new AlipayOrderInfoWrapper.Selecter();
        matcher.orderNoEq(orderId);//等于不同的id,通过点出不同的东西控制
        return alipayOrderInfoMapper.selectOne(matcher);//将wrapper入参
    }

28)经常需要的时间戳(13位),获取毫秒

#### 6.时间戳
 //获得13位时间戳精确到毫秒
        long date = System.currentTimeMillis();
		//阿里开发手册强制推荐:
		//1.获取毫秒数,必须使用
        System.currentTimeMillis();
        //2,而不是
        new Date().getTime();

29)初识配置nacos

java开发杂项总结_第10张图片

30)读取配置类中的值,配置类写法

// 配置类写法一
package com.xfw.docking.proxy.config;

import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * xxl-job配置
 */
@Configuration
public class XxlJobConfig {
    private final Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

    @Value("${xxl.job.admin.addresses}")//通过该注解,${},每一个点表示一层
    private String adminAddresses;

    @Value("${xxl.job.accessToken}")
    private String accessToken;

    @Value("${xxl.job.executor.appname}")
    private String appname;

    @Value("${xxl.job.executor.address}")
    private String address;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @Value("${xxl.job.executor.port}")
    private int port;

    @Value("${xxl.job.executor.logpath}")
    private String logPath;

    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;


    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);

        return xxlJobSpringExecutor;
    }


}

//yml结构

xxl:
	job:
		admin:
			addresses: "ghjhgfhj"


// 配置类写法二
@Configuration
@ConfigurationProperties(prefix = "fulu") //配置中以fulu为前缀的配置
@Data
public class FuluConfigBean {
    private  String appKey;
    private  String appSecret;
    private  String memberCode;
    private  String memberName;
    private  String gateway;
    private  String alipayAccount;
    private  String alipayAccountName;
    private  String transferAmount;
    private  String warningAmount;


}



//yml结构
fulu:
	appKey: "ghjkjhg"
	......

31)项目中的yml配置nacos中的配置

server:
  port: ${APP_PORT:19000}
  servlet:
    context-path: /
spring:
  application:
    name: ${xxl-job-admin.namespace:}xxl-job-admin
  cloud:
    nacos:
      username: ${NACOS_SERVER_USERNAME:nacos}
      password: ${NACOS_SERVER_PASSWORD:xfw1234}
      server-addr: ${NACOS_SERVER_ADDR:172.16.9.159:8848}
      config:
        prefix: xxl-job //nocos中配置的前缀
        enabled: true //启用
        file-extension: yml//nocos中配置的后缀
      discovery:
        enabled: true

  profiles:
    active: @profiles.active@
  main:
    allow-bean-definition-overriding: true

32)nacos中的配置,对标上面的配置

spring:
  datasource:
    url: jdbc:mysql://47.99.39.180:3306/welfare_dev_xxl_job?serverTimezone=CST&useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useInformationSchema=true
    username: root
    password: xinfengwei,2018
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    druid:
      connect-properties:
        config.decrypt: false
        config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKEDoKdvmsSWILeeRuCqu4yjlaPAoKJbrJw1JNoAP20YLZmvC8kl+/bYwLpmog97lO16PELsPMy/ovq5I2fot2cCAwEAAQ==
      filter:
        config:
          enabled: true
        xfw:
          enabled: true
      max-active: 64
      initial-size: 10
      min-idle: 10
      max-wait: 6000
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: select 'X'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
### xxl-job, access token
xxl:
  job:
    accessToken: y@Ylv2fOxX07SgYm
### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")
    i18n: zh_CN

## xxl-job, triggerpool max size
    triggerpool:
      fast:
        max: 200
      slow:
        max: 100
    logretentiondays: 365
    
redis:
    database: 11
    host: 47.99.39.180
    port: 6379
    password: 'xinfengwei,2018'
    timeout: 1000
    lettuce:
      pool:
        max-active: 2
        max-idle: 2
        min-idle: 1
        max-wait: -1
    servlet:
    multipart:
      max-file-size : 20MB
      max-request-size: 100MB
    cloud:
      bus:
        enabled: false

### xxl-job, log retention days
    logretentiondays: 7

environment:
  variable: DEV    

33)postman怎么传json格式

{
    'list'[1,1],//json传集合,数组"flag":1,"msgId": **null**,"title": "测试新建6","content": "新建内容6","imgUrl": "https://img-bss.csdn.net/1640226649214.png","proId": 1,"push": 1,"date": "2020-05-01 01:01:09"//json时间格式

}

34)java后端强行转时间格式

@ApiModelProperty(value = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")//此注解
	private Date created;

35)分页代码

//注意返回结果,注意传参
public PageInfo<MsgFrontPage> queryMsgPage(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);//在这里控制就好了
        List<MsgFrontPage> messagesList = messageMapper.queryMsg();//还是全查出来
        return new PageInfo<>(messagesList);//将查出来的集合进行分页
    }

36)将字符串(string)转化为相应的数据类型的集合(List)

//
int[] ids= Arrays.stream(str.split(",")).mapToInt(s -> Integer.parseInt(s)).toArray();
//转为请求方法对应参数类型
List<Integer> collect = Arrays.stream(ids).boxed().collect(Collectors.toList());

//一个小坑,集合转为字符串之后,每个逗号后还是有空格的,所以在使用split分割的时候需要加空格
//集合转完有空格
long[] longs = Arrays.stream(substring.split(", ")).mapToLong(item -> Long.parseLong(item)).toArray();

集合转数组(阿里开发手册)

【强制】使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一
致、长度为 0 的空数组。
反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现
ClassCastException 错误。
正例:
List<String> list = new ArrayList<>(2);
list.add("guan");
list.add("bao");
String[] array = list.toArray(new String[0]);
说明:使用 toArray 带参方法,数组空间大小的 length: 1) 等于 0,动态创建与 size 相同的数组,性能最好。
2) 大于 0 但小于 size,重新创建大小等于 size 的数组,增加 GC 负担。
3) 等于 size,在高并发情况下,数组创建完成之后,size 正在变大的情况下,负面影响与 2 相同。
4) 大于 size,空间浪费,且在 size 处插入 null 值,存在 NPE 隐患。

37)前端没有长整型,都是string

长整型都是使用string去接收,传long超过16位就会造成精度丢失

38)限制文件上传大小,添加配置文件

servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 20MB
      enabled: true

39)全局版本号的定义(父子工程pom文件的书写)

POM标签大全详解 - Youpeng - 博客园 (cnblogs.com)

//父工程例子
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <packaging>pom</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xfw</groupId>
    <artifactId>welfare</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>welfare</name>
    <description>描述</description>
    //版本号统一管理
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <xfw-framework.version>1.0.15</xfw-framework.version>
        <jjwt.version>0.9.1</jjwt.version>
        <springboot.version>2.3.8.RELEASE</springboot.version>
        <springcloud.version>Hoxton.SR9</springcloud.version>
        <aliyun.openservices.version>1.8.8.Final</aliyun.openservices.version>
        <spring-cloud-alibaba-dependencies.version>2.2.6.RELEASE</spring-cloud-alibaba-dependencies.version>
        <fastjson.version>1.2.66</fastjson.version>
        <lombok.version>1.18.16</lombok.version>
        <redisson.version>3.8.2</redisson.version>
        <mybatisplus.version>3.4.3.2</mybatisplus.version>
        <commons-beanutils.version>1.9.4</commons-beanutils.version>
        <welfare-version>0.0.1-SNAPSHOT</welfare-version>
        <swagger2.version>2.9.2</swagger2.version>
        <knife4j.version>2.0.9</knife4j.version>
        <swagger-models.version>1.5.22</swagger-models.version>
        <dingtalk-sdk.version>2.0.0</dingtalk-sdk.version>
    </properties>
    //父工程模块的管理子模块工程,与删除添加同步
    <modules>
        <!--网关-->
        <module>welfare-gateway</module>
        <!--商品-->
        <module>welfare-product</module>
        <!--商品对外api-->
        <module>welfare-product-api</module>
        <!--订单-->
        <module>welfare-order</module>
        <!--订单对外api-->
        <module>welfare-order-api</module>
        <!--三方璐付对接-->
        <module>welfare-lf</module>
        <!--璐付对外api,同代理proxy对接-->
        <module>welfare-lf-api</module>
        <!--通用-->
        <module>welfare-common</module>
        <!--代码生成-->
        <module>welfare-generator</module>
        <!--同步、下单、状态、代理项目,针对实体-->
        <module>welfare-docking-proxy</module>
        <!--xxl-job主项目-->
        <module>xxl-job-admin</module>
        <!--xxl-job核心包-->
        <module>xxl-job-core</module>
        <!--运营端-->
        <module>welfare-operation</module>
        <!--企业端-->
        <module>welfare-enterprise</module>
        <!--系统管理-->
        <module>welfare-system</module>
        <!--系统管理api-->
        <module>welfare-system-api</module>
        <!--消息模块-->
        <module>welfare-message</module>
        <!--消息模块api -->
        <module>welfare-message-api</module>
        <!--鉴权 -->
        <module>welfare-authentication</module>

        <module>welfare-auth</module>
        <module>welfare-auth-api</module>
        <module>welfare-push</module>
    </modules>
    //dependencyManagement:依赖管理,这是父工程需要使用的,有时内部依赖可能会爆红,可以把			    dependencyManagement删除重新down依赖即可,然后重新添加标签
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${springboot.version}</version>//引入版本号的格式
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${springcloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba-dependencies.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.aliyun.openservices</groupId>
                <artifactId>ons-client</artifactId>
                <version>${aliyun.openservices.version}</version>
            </dependency>
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>${jjwt.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <scope>provided</scope>
            </dependency>

            <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson</artifactId>
                <version>${redisson.version}</version>
                <optional>true</optional>
            </dependency>

            <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson-spring-boot-starter</artifactId>
                <version>${redisson.version}</version>
            </dependency>

            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatisplus.version}</version>
            </dependency>

            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus</artifactId>
                <version>${mybatisplus.version}</version>
            </dependency>

            <dependency>
                <groupId>commons-beanutils</groupId>
                <artifactId>commons-beanutils</artifactId>
                <version>${commons-beanutils.version}</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.21</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.23</version>
            </dependency>
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>${gson.version}</version>
            </dependency>

            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>${swagger2.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>io.swagger</groupId>
                        <artifactId>swagger-annotations</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.swagger</groupId>
                        <artifactId>swagger-models</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-models</artifactId>
                <version>${swagger-models.version}</version>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-annotations</artifactId>
                <version>${swagger-models.version}</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>${swagger2.version}</version>
            </dependency>

        </dependencies>
    </dependencyManagement>
    //依赖引入
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

//子工程例子
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        
     
     //父工程标签
    <parent>
        <artifactId>welfare</artifactId>
        <groupId>com.xfw</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>welfare-message</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    
             
             
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>archaius-core</artifactId>
                    <groupId>com.netflix.archaius</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>HdrHistogram</artifactId>
                    <groupId>org.hdrhistogram</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>commons-io</artifactId>
                    <groupId>commons-io</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
        <!-- freemarker-starter -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>com.xfw</groupId>
            <artifactId>welfare-common</artifactId>
            <version>${welfare-version}</version>
            //去除依赖中的某个依赖
            <exclusions>
                <exclusion>
                    <groupId>com.xfw.framework</groupId>
                    <artifactId>xfw-framework-leopard-auth</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.xfw</groupId>
            <artifactId>welfare-authentication</artifactId>
            <version>${welfare-version}</version>
        </dependency>
        <dependency>
            <groupId>com.xfw</groupId>
            <artifactId>welfare-message-api</artifactId>
            <version>${welfare-version}</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>dingtalk</artifactId>
            <version>1.2.5</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.xfw.framework</groupId>
            <artifactId>xfw-framework-leopard-dingtalk-base</artifactId>
            <version>${xfw-framework.version}</version>
        </dependency>
        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-job-core</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    
             
    <repositories>
        <repository>
            <id>maven-central</id>
            <name>maven-central</name>
            <url>http://47.99.39.180:8781/repository/maven-releases/</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
    </repositories>
    <profiles>
        <profile>
            <!-- 本地开发环境 -->
            <id>dev</id>
            <properties>
                <profiles.active>dev</profiles.active>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <!-- 测试环境 -->
            <id>test</id>
            <properties>
                <profiles.active>test</profiles.active>
            </properties>
        </profile>
        <profile>
            <!-- 生产环境 -->
            <id>pro</id>
            <properties>
                <profiles.active>pro</profiles.active>
            </properties>
        </profile>
        <profile>
            <!-- 预发环境 -->
            <id>pre</id>
            <properties>
                <profiles.active>pre</profiles.active>
            </properties>
            <build>
                <resources>
                    <resource>
                        <directory>src/main/resources/pre</directory>
                    </resource>
                </resources>
            </build>
        </profile>
    </profiles>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>build-info</goal>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <appendAssemblyId>false</appendAssemblyId>
                    <descriptors>
                        <descriptor>src/main/assembly/assembly.xml</descriptor>
                    </descriptors>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <nonFilteredFileExtensions>ttf</nonFilteredFileExtensions>
                    <nonFilteredFileExtensions>pdf</nonFilteredFileExtensions>
                </configuration>
            </plugin>

            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>package</phase>
                        <configuration>
                            <tasks>
                                <copy todir="../target">
                                    <!-- project.build.directory表示各个模块的target目录 -->
                                    <fileset dir="${project.build.directory}">
                                        <!-- 需要复制的jar包文件名称 -->
                                        <include name="${project.artifactId}-${project.version}.jar"/>
                                    </fileset>
                                </copy>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml
                
                false
            
            
                src/main/resources
                
                    **/*.yml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>false</filtering>
                <includes>
                    <include>fonts/*
                
            
            
                src/main/resources
                true
                
                
                    test/*
                    pro/*
                    pro/*
                    dev/*
                    fonts/*
                
            
            
                src/main/resources/${profiles.active}
            
        
    


40)swagger接口文档的注意事项

1.详细,清楚

2.有状态接口文档需要枚举(如:有状态1,2,3;需要标明1,2,3的具体意思)

41)api中要求url拼接的参数形式(以钉钉发送消息模板发送data为例)

java开发杂项总结_第11张图片

private Map<String, String> advanceBody(Date startTime, String corpId, String subjectName, Long courseId, String courseName, String coursePlanTitle,
                                        String teacherName, Integer classDuration, String role) {

    Map<String, String> body = Maps.newHashMap();
    body.put("startTime", DateUtil.dateToString(startTime, DateUtil.HH_MM));
    body.put("subjectName", subjectName);
    body.put("courseName", courseName);
    body.put("coursePlanTitle", coursePlanTitle);
    body.put("teacherName", teacherName);
    body.put("classDuration", classDuration + "");
    body.put("title", "【上课提醒】");
    // 构造dingtalk链接
    body.put("h5Url", getMsgUrl(false, role, corpId, courseId));
    body.put("pcUrl", getMsgUrl(true, role, corpId, courseId));
    return body;
}
/**
     * 拼接data
     *
     * @param msgType
     * @param title
     * @param image
     * @param content
     * @param messageUrl
     * @return
     */
    public String advanceBody(String msgType, String title, String image, String content, String messageUrl) {
        Map<String, String> body = Maps.newHashMap();
        body.put("msgType", msgType);
        body.put("title", title);
        body.put("image", image);
        body.put("content", content);
        body.put("messageUrl", messageUrl);
        return JSON.toJSONString(body);//需要string,就把map转成string,不能硬拼接需要使用map
    }

42)拼接固定参数url,java Api(StrSubstitutor)指定字符拼接,${}符号中的占位符

//${agentId}必需以${}的形式存在,占位符
    public static void main(String[] args) {
        String url="dingtalk://dingtalkclient/action/open_micro_app?corpId=${corpId}&agentId=${agentId}&miniAppId=%s&pVersion=1&packageType=1&page=%2Fpages%2Fgoods%2Fgoods%3FproductsId%3D";
        HashMap<Object, Object> map = new HashMap<>();
        map.put("corpId",122);
        map.put("agentId",1222);
        //参数为map,代替字符串中的对应位置,占位符
        StrSubstitutor strSubstitutor = new StrSubstitutor(map);
        String str = strSubstitutor.replace(url);
        System.out.println(str);
    }

43)SpringCloud Feign 传参问题及传输Date类型参数的时差(未能解决,换了方法)

44)sql语句优化(数据库优化,待学习)

1.查看sql执行过程
//sql执行过程 EXPLAIN关键字
EXPLAIN	select `id`, `corp_id`, `agent_id`, `suite_id`, `ding_user_id_added`, `create_time`, `update_time`, `auth_status`, `service_status`, `is_delete` from sys_corp_suite GROUP BY corp_id
			
			
EXPLAIN select id from sys_corp_suite where id='123456789'
2.结果

java开发杂项总结_第12张图片

45)java8新特性对比(流的方式拿出集合中对应的指定属性,写法上的优化)

  //循环拿出userId
//所要操作的集合
List<SysCorpSuite> userList = sysCorpSuiteApi.findAddUser(item.getCorpId());

//1。lambda表达式
            List<String> useridList = userList.stream().map(user -> {
                String dingUserId = user.getDingUserIdAdded();
                return dingUserId;
            }).collect(Collectors.toList());

//2。优化写法
List<String> useridList = userList.stream().map(SysCorpSuite::getDingUserIdAdded).collect(Collectors.toList());

46)JAVA中常量使用常量类或者常量接口,还是使用枚举的区别

(具体情况具体分析,参考阿里巴巴开发手册)建议使用枚举类 https://blog.csdn.net/chenpeng19910926/article/details/76210117

47)浮点数之间的等值判断,不能使用==或equals使用方法

https://www.jianshu.com/p/dfc3ec4350e6(参考博客) 详见阿里巴巴开发手册

【强制】浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用 equals
来判断。
说明:浮点数采用“尾数+阶码”的编码方式,类似于科学计数法的“有效数字+指数”的表示方式。二进
制无法精确表示大部分的十进制小数,具体原理参考《码出高效》。
反例:
float a = 1.0F - 0.9F;
float b = 0.9F - 0.8F;
if (a == b) {
 // 预期进入此代码块,执行其它业务逻辑
 // 但事实上 a==b 的结果为 false
}
Float x = Float.valueOf(a);
Float y = Float.valueOf(b);
if (x.equals(y)) {
 // 预期进入此代码块,执行其它业务逻辑
 // 但事实上 equals 的结果为 false
}
正例:
(1) 指定一个误差范围,两个浮点数的差值在此范围之内,则认为是相等的。
float a = 1.0F - 0.9F;
float b = 0.9F - 0.8F;
float diff = 1e-6F;
if (Math.abs(a - b) < diff) {
 System.out.println("true");
}
(2) 使用 BigDecimal 来定义值,再进行浮点数的运算操作。
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
BigDecimal x = a.subtract(b);
BigDecimal y = b.subtract(c);
if (x.compareTo(y) == 0) {
 System.out.println("true");
}

48)各种数据类型之间的比较方法选用【==和equals并不是全部适用的】(阿里巴巴见开发手册)

49)遍历map集合的(4+1种)【还有一个事java8:map.forEach】

尽量使用entrySet ,java8中推荐是红map.forEach((key,value)->{}), 详情参照阿里开发手册

50)一边循环一边删除集合中的数据(必须使用迭代器,不能使用forEach)

 while (iterator.hasNext()) {
             String id = iterator.next();
             if (!sysUserProductSettingApi.getMsgUserProductSetting(Long.valueOf(id))) {
                    iterator.remove();
                }
            }

51)递归拿捏(迷宫问题,理解小测试)

package com.example.l220109.my;

import org.junit.Test;

/**
 * @author xusj
 * 
CreateDate 2022/2/10 0:41 */
public class Rucursion { /** *
     * 迷宫问题求解
     * 
*/
@Test public void demo() { // 构建一个 8 行 7 列的地图 int[][] map = initMap(8, 7); printMap(map); // 一次性没有回溯的路线 setWay(map, 1, 1, 6, 5); // 这个点,是有回溯的路线 // setWay(map, 1, 1, 4, 1); System.out.println("路线查找完毕"); printMap(map); } /** *
     *  思路说明:
     *  1. 从 startX,startY 开始走,到 endX,endY 结束
     *  2. 当走到 endX,endY 时,表示已经找到了路线
     *  3. 约定:map 中的含义:
     *      0:表示该点没有走过
     *      1:表示围墙,不能走
     *      2:表示改点已走过,并且可以走
     *      3:表示改点已走过,但是走不通
     *
     *  4. 走迷宫,约定一个寻找路线的策略,也就是当你站在一个点的时候,你从哪一个方向开始探索?
     *     这里规定探索的方向为:下 -> 右 -> 上 -> 左,如果该点走不通,再回溯
     * 
* * @param map 代表一张地图 * @param startX 从哪一个点开始走 * @param startY * @param endX 到哪一个点结束 * @param endY * @return true: 表示该点可以走,false:表示改点不能走 */
public boolean setWay(int[][] map, int startX, int startY, int endX, int endY) { // 如果当结束点已经走过,表示已经到达了出口 // System.out.println(); // printMap(map); // 打开这个可以看到每一步的探索路径 if (map[endX][endY] == 2) { return true; } // 那么开始我们的策略探索 // 如果该点还没有走过,则可以尝试探索 if (map[startX][startY] == 0) { // 先假定该点标可以通过,因为要去探索四周的点是否可以走 map[startX][startY] = 2; // 下 -> 右 -> 上 -> 左 // 根据策略:先往下走,如果可以走则返回 true if (setWay(map, startX + 1, startY, endX, endY)) { return true; } // 如果走不通,则继续往右边探索 else if (setWay(map, startX, startY + 1, endX, endY)) { return true; } // 如果走不通,则继续往上边探索 else if (setWay(map, startX - 1, startY, endX, endY)) { return true; } // 如果走不通,则继续往左边探索 else if (setWay(map, startX, startY - 1, endX, endY)) { return true; } // 都走不通,表示改点是一个死点,四周都无法出去 else { map[startX][startY] = 3; return false; } } else { // 如果不为 0,可能的情况是:1,2,3,这三种表示都表示不可以走 return false; } } /** * 构建一个有挡板的地图 *
     * 数字 1:表示挡板围墙,小球不可以经过
     * 数字 0:表示是路,小球可以经过
     * 起点:可以自定义起点
     * 出口:其实也可以自定义出口,但是本题规定,出口就是右下角的 0
     * 1 1 1 1 1 1 1
     * 1 0 0 0 0 0 1
     * 1 0 0 0 0 0 1
     * 1 1 1 0 0 0 1
     * 1 0 0 0 0 0 1
     * 1 0 0 0 0 0 1
     * 1 0 0 0 0 0 1
     * 1 1 1 1 1 1 1
     * 
* * @return */
private int[][] initMap(int row, int cloum) { // 构建一个 8 行 7 列的地图 int[][] map = new int[row][cloum]; // 数字 1 表示挡板,构建一个有挡板的地图 for (int i = 0; i < map[0].length; i++) { map[0][i] = 1; // 顶部增加挡板 map[map.length - 1][i] = 1; // 底部增加挡板 } for (int i = 0; i < map.length; i++) { map[i][0] = 1; // 左侧增加挡板 map[i][map[0].length - 1] = 1; // 右侧增加挡板 } // 中间的其他固定挡板 map[3][1] = 1; map[3][2] = 1; return map; } public void printMap(int[][] map) { for (int i = 0; i < map.length; i++) { for (int j = 0; j < map[0].length; j++) { System.out.print(map[i][j] + " "); } System.out.println(); } } /*** * 理解小测试 * * @param args * @author xusj *
CreateDate 2022/2/10 1:10 */
public static void main(String[] args) { int i = 7; // test(7); test2(7); } public static void test(int s) { // 是递归 if (s > 1) { test(s - 1); } System.out.println(s); } public static void test2(int j) { // 是递归 if (j == 1) { return; } else { test2(j - 1); System.out.println(j); } } }

52)专业词汇类目,spu,sku

类目:类目是一个树状结构的系统,大体上可以分成4-5级。如手机->智能手机->苹果手机类目,在这里面,手机是一级类目,苹果手机是三级类目,也是叶子类目。

SPU:苹果6(商品聚合信息的最小单位),如手机->苹果手机->苹果6,苹果6就是SPU。

SKU:土豪金 16G 苹果6 (商品的不可再分的最小单元)。

从广义上讲,类目>SPU>SKU。

53)sql模糊搜索,索引问题

索引与优化like查询

  1. like %keyword 索引失效,使用全表扫描。但可以通过翻转函数+like前模糊查询+建立翻转函数索引=走翻转函数索引,不走全表扫描。
  2. like keyword% 索引有效。
  3. like %keyword% 索引失效,也无法使用反向索引。

54)说说count(*)、count(1)、count(列名)有什么区别?

https://juejin.cn/post/6854573219089907720

55)xml多条件模糊查询

<select id="getAllRegisterUser"
        resultType="cn.org.bjca.econtract.commonbusiness.model.polymerization.dto.UserManagerListDto">
    SELECT
    a.user_name,
    a.mobile,
    a.create_time,
    b.state
    FROM
    cb_uc_user_register a
    LEFT JOIN cb_uc_user_register_extends b ON a.id = b.user_id
    <where>
     <if test="userManagerListDto.userName != null and userManagerListDto.userName !=''">
            AND a.user_name like concat('%', #{userManagerListDto.userName},'%')
      </if>
      <if test="userManagerListDto.state != null and userManagerListDto.state != ''">
            AND b.state = #{userManagerListDto.state}
      </if>
    </where>

56)url拼接

dingtalk://dingtalkclient/action/open_micro_app?corpId=KaTeX parse error: Expected 'EOF', got '&' at position 9: {corpId}&̲agentId={agentId}&miniAppId=%s&pVersion=1&packageType=1&page=%2Fpages%2Fgoods%2Fgoods%3FproductsId%3D

dingtalk://dingtalkclient/action/open_micro_app?corpId=%s&agentId=%s&miniAppId=%s&pVersion=1&packageType=1&page=%s

57)MyBatisPlus多条件查询,组合查询

https://www.cnblogs.com/BNTang/articles/14584735.html

58)前后端交互Long和string

【强制】对于需要使用超大整数的场景,服务端一律使用 String 字符串类型返回,禁止使用 Long 类型

说明:Java 服务端如果直接返回 Long 整型数据给前端,JS 会自动转换为 Number 类型(注:此类型为双

精度浮点数,表示原理与取值范围等同于 Java 中的 Double)。Long 类型能表示的最大值是 2 的 63 次方

-1,在取值范围之内,超过 2 的 53 次方 (9007199254740992)的数值转化为 JS 的 Number 时,有些数

值会有精度损失。扩展说明,在 Long 取值范围内,任何 2 的指数次整数都是绝对不会存在精度损失的,所

以说精度损失是一个概率问题。若浮点数尾数位与指数位空间不限,则可以精确表示任何整数,但很不幸,

双精度浮点数的尾数位只有 52 位。

反例:通常在订单号或交易号大于等于 16 位,大概率会出现前后端单据不一致的情况,比如,“orderId”:

for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}

/***
 * 理解小测试
 *
 * @param args
 * @author xusj
 * 
CreateDate 2022/2/10 1:10 */ public static void main(String[] args) { int i = 7;

// test(7);
test2(7);
}

public static void test(int s) {
    // 是递归
    if (s > 1) {
        test(s - 1);
    }
    System.out.println(s);


}

public static void test2(int j) {
    // 是递归
    if (j == 1) {
        return;
    } else {
        test2(j - 1);
        System.out.println(j);
    }
}

}


#### 52)专业词汇类目,spu,sku

类目:类目是一个树状结构的系统,大体上可以分成4-5级。如手机->智能手机->苹果手机类目,在这里面,手机是一级类目,苹果手机是三级类目,也是叶子类目。

SPU:苹果6(商品聚合信息的最小单位),如手机->苹果手机->苹果6,苹果6就是SPU。

SKU:土豪金 16G 苹果6 (商品的不可再分的最小单元)。



从广义上讲,类目>SPU>SKU。



#### 53)sql模糊搜索,索引问题

索引与优化like查询

1. like %keyword    索引失效,使用全表扫描。但可以通过翻转函数+like前模糊查询+建立翻转函数索引=走翻转函数索引,不走全表扫描。
2. like keyword%    索引有效。
3. like %keyword% 索引失效,也无法使用反向索引。





#### 54)说说count(*)、count(1)、count(列名)有什么区别?

https://juejin.cn/post/6854573219089907720



#### 55)xml多条件模糊查询

```java