Java-Debug记录1-10条

1. Java文件读取路径解析

首先,凡是遇到需要确定文件路径的问题,不可或缺的代码是:System.out.println(System.getProperty("user.dir"))

在IDEA下,Java的文件路径读取分为两种类型:

  1. “/xxx”:代表着自classpath开始,也就是当前运行代码在out文件夹下所处的母文件夹位置,比如说:
    在这里插入图片描述
    我在src文件中运行TCPClientDemo,此时"/"代表着前述绝对路径为:
    在这里插入图片描述
    out文件下直到Network的路径信息

  2. “xxx”:而不加/的路径,代表的则是project的根目录,也就是说前述绝对路径直到project根目录为止

2. Mybatis中,#{}和${}的使用区别

在本人的另一篇博客中,我有对JDBC中PreparedStatement的思想和作用有所总结,其核心的实现就是对特殊字符做转义处理,但这也意味着,我们无法使用String等字段作为传入参数,实现拼字符串的效果。比如以下的Sql语句:

select * from ? where id = ?;

我们想设置第一个?为表名,于是通过set方法传入了一个String类型参数,但是最后拼接而成的字符串是:

select * from 'tableName' where id = ?

set方法的处理逻辑注定了我们无法像拼字符串一样自动去掉单引号,从而使得上述SQL无法查询到结果

在Mybatis中,#{}就对应了PreparedStatement中的set方法,所以它也无法处理需要自动去掉单引号的场景,这个时候就需要${}来完成工作了,也就是在配置xml文件中写下如下的一段sql语句:

select * from ${tableName} where id = #{id};

当然,还要注意传参的时候使用@Param来指定hashMap映射时的key,否则会报无法找到对应字段的错误

但是,使用${}不可避免地都会有SQL注入风险,这个时候最好的办法就是增加对输入字段格式的判断,对不符合规范的输入做打回处理

3. 使用中文时,java程序中查不到数据,同样sql语句放数据库中可以查到

在确定了Java与Mysql中有关于中文字段都是使用的UTF-8编码(打印了直接赋值与获取Mysql中字段后的String类型的byte,完全相同),利用模糊查询,根据特定条件访问数据库仍然无法得到想要的数据,最后,发现原因是:

mysql的字符集有问题,编码方式不支持中文,因此必须在MyBatis的配置文件中,修改url为支持UTF-8编码格式

<property name="url" value="jdbc:mysql:///${tableName}?useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false"/>

&amp;&的转义字符

修改后可以查询出对应编码的中文在Mysql中的数据

4. Filter以及浏览器解析资源的分析

如果我们有以下的需要:通过Filter来完成登陆过滤的功能,对服务器所有资源的访问都必须在登录后进行,否则跳转至登录页面

我们通过判断用户名是否存在于Session中完成了登录辨识的任务,但是在通过请求转发来处理未登录的跳转时,我不禁对以下代码产生了疑问:

req.getRequestDispatcher("login.jsp").forward(servletRequest,servletResponse);

login.jsp中,关联有样式相关的CSS文件图片文件,我们通过请求转发向用户返回了一个jsp文件信息,浏览器在解析之后,会继续向服务器请求对应路径下的CSS文件图片文件,这时候,所写过滤器会直接过滤掉该请求(因为还没有登陆),从而执行上面的请求转发代码。

疑问就是:如果再一次返回login.jsp,那么浏览器在解析之后,不是又会发现缺少CSS文件图片文件,从而不断往复的请求吗?

通过实验,我们发现在请求CSS文件未果后,浏览器端报的是404错误,因此response并不是我们以为的login.jsp,而是Tomcat生成的报错信息。

由此我们分析,应该是Tomcat有一个纠错环节,它会判断浏览器发起的请求文件后缀与响应的文件后缀是否一致,如果不一致,那么即使你有响应信息,Tomcat也会自动生成404错误(也就不存在我们设想中的不断请求的问题了)

为了证明Tomcat只认后缀不认文件名,我们试过访问login.css的时候,请求转发的是register.css,响应字段为200,由此证明我们的想法是正确的

5. static关键字

static关键字声明了在对象调用的时候就执行,且只执行一次的代码

如果不声明static关键字,则对象中的方法想要被调用,就必须先实例化对象

6. Idea下Maven项目依赖;Druid判断连接是否成功

在书写Spring容器的注解开发代码的时候,创建DruidDataSource总是不成功,报各种错,遇到的错误大致分为以下类别:

1. java.sql.SQLException: Cannot load JDBC driver class 'com.mysql.jdbc.Driver'
2. NullPointerException

第一个错误就是今天要讲的Idea下Maven项目依赖的问题而导致。在进行注解开发的时候,我没有创建新的项目,而是在之间已经有的一个项目包(包中有一个其他的模块)下新建的模块,然后再在该模块中配置的pom.xml。这种情况下,我在pom.xml不管进行多少次配置,由于项目目录没有更正,所以总是出现mysql的jdbc.Driver找不到的情况。

要解决该问题,最简单的办法就是重新创建一个空项目,把你的模块导入进去,这样就避免了去查半天Idea项目工作路径相关的知识

第二个错误是空指针错误,最开始我无法定位到底是Druid没有连接上,还是我写的Dao有问题,因为我不知道如何判断Druid是否连接成功。后面经过查询后,我得知了一个判断Druid是否连接成功的方法:

// 测试连接池是否连接成功
DataSource dataSourceBean = container.getBean(DataSource.class);
Connection connection = dataSourceBean.getConnection();
System.out.println(connection);

通过DruidDataSource的getconnection方法是否有输出,可以判断连接成功与否

这里,错误产生就是Druid没有连接上的原因,然后我去查看了我的property文件书写,原来是格式错误,在赋值的时候,加了双引号,而property文件赋值不需要加双引号,去掉后测试连接已成功

7. nacos集群报错:tried errcode 400

当时看到400状态码,下意识的就认为是因为客户端代码出现了问题,其实是不对的

先说一下出现400报错,而客户端代码又没问题的情况下,最大可能是在配置nacos集群时,使用的是localhost作为地址,与nacos读取到的ip地址不匹配。

这一点可以去查看启动nacos集群时,集群节点信息,如果你发现有一个[ipv4地址]的节点,而其他的则是[localhost]节点,恭喜你,你的错误不是来自于客户端代码,而是配置nacos集群的地址问题。

这个问题的原理就是,nacos读到的[ipv4地址]与你设置的集群localhost不匹配,所以在出错的环境下去查看nacos/conf/cluster.conf文件,你会发现如下信息:

[ipv4]:[portx]
localhost:[port1]
localhost:[port2]
localhost:[port3]

明明只配了3个nacos节点,但却无中生有了一个[ipv4]:[portx]节点(其实它与localhost:[portx]完全等价),这就会导致nacos集群无法应对访问,为什么一个重复节点的设置就会导致nacos集群无法工作的内部的原因暂时不明,猜测可能是与自检机制有关

因此,解决方法很简单,将所有cluster.conf中的localhost配置为[ipv4],(nginx中不用修改,因为[ipv4]其实是等价于localhost的,只是nacos不认)然后重启集群。

这时候去nacos集群节点信息中查看,就只有3个节点信息了,问题解决,注册不再有400报错

7. com.alibaba.fastjson.JSONException: not match : - =

出现这个异常的原因是JSON字符串和要转换的JAVA对象并不匹配,该问题常见的产生场景,例如JAVA对象中缺失了字段,或者某个字段没有设置或屏蔽了Setter方法,这些场景是比较好排查出来的

还有一种常见但是难以注意到的产生场景,那就是要转换的JSON字符串的字段和值描述的时候缺少了双引号,常见于调用某些API时,没有正确选择能返回JSON String的方法,例如在使用elasticsearch中的getSource时,返回值如下:

"{name:xyz}"

这就是缺少双引号的情况,Fastjson在解析时无法读取到对应字段。因此,如果排查发现是这个问题,那么解决一般从两个方面入手:如果提供了返回String的API,如getSourceString,那么就换成这个方法;如果没有提供,则需要自己编写转换的方法

8. systemctl restart docker卡住不动

##  查看所有docker相关的进程id
[root@homeforzhu ~]# ps -ef | grep docker

## 一步步kill所有进程
[root@homeforzhu ~]# kill -9 [id]

## 再次尝试重启
[root@homeforzhu ~]# systemctl restart docker

9. LocalDateTime在parsed时,由于空格引起的"index 10"报错

具体报错为:"Text '2022-11-15 00:00:00' could not be parsed at index 10"

index10是什么,数一数上面的时间字符串就会发现index10正是指的空格字符,ASCII码为\32

出现该报错的原因在于:LocalDateTime在使用parse序列化String字符串为LocalDateTime类型时,要求字符串以’T’,ASCII码为\84来分隔日期和时间,如果使用空格就会出现could not be parsed at index 10的报错

并且,LocalDateTime自己所提供的反序列化工具,也是默认将LocalDateTime类型反序列化为以’T’分隔的String字符串,如果不做处理,返回给前端的日期字符串格式将是yyyy-MM-dd'T'HH:mm:ss

就目前所知,我们无法通过设置使得LocalDateTime可以去序列化与反序列化yyyy-MM-dd HH:mm:ss格式的String字符串,要处理成yyyy-MM-dd HH:mm:ss格式,只能通过设置JSON字符串与Java对象的序列化与反序列化来实现,详情参见:全局设置LocalDateTime->JSON的Format

而String字符串想序列化成LocalDateTime,只能手动的将空格替换为’T’

StringBuilder stringBuilder = new StringBuilder((CharSequence) dateTime);
stringBuilder.setCharAt(10, 'T');

10. 实体类Id为Long类型,且Id生成方法为雪花算法时(即ASSIGN_ID),传至前端未出现损失,但由前端传回时,末两位被截断为00

问题解决参考自:后端id设置long类型时,传到前端,超过19位最后两位为00
这是由于javascript的Number类型和java的long类型最大长度不同导致的

JavaLong的取值范围为-92233720368547758089223372036854775807(即-2^64“ 到”2^64-1
JavaScript中的Number取值范围为-90071992547409929007199254740991 (即-2^532^53-1

要解决该问题,只需要设定java对象序列化为JSON时,将Long类型转成String类型

@JsonSerialize(using = ToStringSerializer.class)
private Long id;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值