一、Java
1. Excel文件导出中文名称时被转义
1 | String fileName = URLEncode.encode(name, "UTF-8"); |
文件的下载在响应之前要设置以 附件(attachment) 的形式,否则点击下载时会在浏览器打开。
Spring MVC 默认的上传文件大小(max-request-size)最大为10M,可以在配置文件中修改。
二、Spring
1. Spring Security 5.x 跨线程获取用户信息
使用 Spring Security 时,如果采用异步方法获取用户信息是获取不到的,它采用 ThreadLocal 存储,这样的话有些请求无法顺利执行,可以在 Spring Boot 启动类主方法添加:
1 | public static void main(String[] args) { |
Spring Security 6.x+ 版本不推荐此方式,推荐传递 context 到子线程或者异步线程中再获取信息;
2. @RestControllerAdvice + swagger 导致的问题
如果在项目中实现 ResponseBodyAdvice
接口统一封装 controller 返回的接口,访问 swagger 地址时会出现弹窗 Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway
的问题。
需要在实现 ResponseBodyAdvice
的类注解上额外加入 @RestControllerAdvice(basePackages = "xxx.xx.controller")
限定需要对返回结果进行封装的范围,这样的话就不会拦截 swagger 相关资源的地址,访问就正常了。
也可以下面这样修改(浪子没有测试,具体见:https://juejin.cn/post/6921700441038258189):
1 |
|
3. 跨域
1 | // 注解用在 Controller 类中,该类所有方法允许其它域中进行访问 |
1 |
|
1 |
|
4. 在 Filter 中注入 Spring Bean
在 Spring Web 中,执行顺序是 context-param–>listener–>filter–>servlet,可以看到 servlet 是在最后的,所以在 Filter 中注入 Bean 的时候就会报 NPE,如果是 SpringBoot 项目,可以在 Filter 的实现类上使用 @Order 注解延迟加载,让 Bean 先行加载,这样就可以在 Filter 中注入了。
5. Spring AOP 和 Spring Security 6.X
1 | Cannot invoke "org.apache.commons.logging.Log.isDebugEnabled()" because "this.logger" is null |
背景:多模块项目,AOP 依赖在 common
模块,Security 在 system
模块,system 依赖于 common。使用 @Aspect
定义了切面和日志,但是定义切入点的时候是 execution(* com.xxx..*.*(..))
。com.xxx
项目是顶级包。
而 Security 中的 OncePerRequestFilter
继承的 GenericFilterBean#init()
中有如下代码:
1 | if (logger.isDebugEnabled()) { |
在进行切入的时候,把这里的 logger
给覆盖了,导致一直拿不到值,项目启动就抛出了 NPE。
修改很简单,打印日志一般抓 controller
层,只需要把切入点定义改为:execution(* com.xxx.controller..*.*(..))
。更加推荐的是把 AOP 依赖直接移入 system
中,相关的日志类也放到该模块,这里出现错误是因为之前的划分原本就不是很合理。
三、MyBatis/MyBatis Plus(MP)
在 SQL 文件中使用了 resultType="java.util.map"
,并且不止一处使用,那么凡是使用 resultType
或者 resultMap
这种属性的标签,不能有属性指向错误,否则就会报错: “Result Maps collection does not contain value for ……”
不能在 mybatis 的 sql.xml
中的 sql 标签(<select>、<update>、<delete>等
)中注释 sql 语句,如果注释的语句中 带有参数,那么就会报这个错误。如果有必须注释的语句,把相关语句复制一份放在 mybatis 标签外面使用<!-- 注释 sql 内容 -->
注释。如果可以,还是把 SQL 语句存储在外部的 txt 等文本文件里。
有这个错误的话就是 mapper 接口和对应的 xml 文件没有绑定,或者绑定了,但是 xml 文件不是在 resources/mapper
路径下。需要在项目的 pom.xml
中添加以下内容:
1 | <!-- 把 xml 文件一起打包 --> |
1. $ And #
这个我想很多人都知道使用哪个比较好了,说说问题。具体语句省略,请注意循环内的条件。
1 | select * from user u |
上面的语句在循环中使用了 ${}
,我把它修改成了 #{}
,但是输入的筛选的条件是不会生效的,继而没有返回数据。
之后看了看它传的参数,发现接口接收的字符串,然后在业务层转为字符串集合,并且为每个元素加入单引号后传入 SQL 的。
1 | private static List<String> getParamList(String propertyType) { |
于是猜想可能就是这个原因导致查询条件不生效,于是把这段代码改成了下面的样子:
1 | private static List<String> getParamlist(String str) { |
这段代码没有给分割后的字符加入英文单引号,map 方法对每一个元素都去掉前后的空格(请结合自身业务场景确定参数是否可包含空格,浪子这里不需要),然后再次测试该接口,perfect!it is working now!
之后使用修改后的字符转集合方法代码再次使用 ${}
去测试,发现 SQL 语句查询又不生效了。。。
于是浪子明白了:使用 ${}
时,参数为 List 类型需要我们为每个元素手动加入单引号,使用单引号包裹才会生效;而使用 #{}
时,List 参数类型则不需要我们手动加入英文单引号,直接传入 List 即可。
2. 接口传参报错
错误信息:
1 | No primary or default constructor found for interface java.util.List] |
后端使用 List<String>
或者数组接参数收时,前端传入数组接收不到;但是可以传字符串,每个元素可以使用英文 ,
分割。
3. MP插入或更新null值
当使用 Mybatis Plus 时,更新数据为 null 值时,即使数据库的字段设置为可以为 null,但是更新或插入时还是数据更新失败。这个就涉及到字段验证策略了。MP 官网也给出了 解决办法
4. mapper.xml
在 mapper.xml
中编写 SQL 语句时有部分字符需要转义才可以被框架正确的解析:
转义字符 | 含义 | 说明 |
---|---|---|
> | > | greater than |
< | < | less than |
& | & |
也可以使用 <![CDATA[]]>
来声明语句,被这个标记所包含的内容将表示为纯文本。