IDEA 提示: Unchecked call to ‘XXXX’ as a member of raw type ‘XXXX’ more… (Ctrl+F1)
1 | Unchecked call to 'ApiResponse(T)' as a member of raw type 'mis.api.common.model.response.ApiResponse' |




复制警告信息

SpringBoot 查询时间数据,数据库和返回数据比实际存储的相差8小时
我遇到的情况:通过 spring security 查询用户时间数据(MySQL 数据库,字段类型为:datetime),返回的数据比实际存储在数据里的多8小时。1
UserDetailsService.loadUserByUsername(username);
serverTimezone=GMT,改为:serverTimezone=GMT%2b8
,其中 %2b
为 + 号
如果还没加参数 serverTimezone,则添加上。
spring boot 项目,@RestController 返回系统时间,比实际时间多8小时
如:1
2
3
4
5
6
7{
"timestamp": "2019-06-23T14:48:55.093+0000", # 这里比实际的系统时间少了8小时
"status": 500,
"error": "Internal Server Error",
"message": "账号不存在",
// some other code
}
原因:spring 转 json 的默认实现 jackson 中会根据时区去转换时间,而 jackson 的默认时区跟国内是相差8小时的。
- 相差8小时实测:
- 比数据库多8小时
- 比通过 spring boot 取到的系统时间时间少8小时
解决
设置时区1
2
3
4
5
6
7#application.properties文件配置
spring.jackson.time-zone=GMT+8
#application.yml文件配置
spring:
jackson:
time-zone: GMT+8
maven 跳过单元测试
在使用 mvn package
进行编译、打包时,Maven会执行 src/test/java
中的 JUnit 测试用例,有时为了跳过测试,会使用参数 -DskipTests
和 -Dmaven.test.skip=true
,这两个参数的主要区别是:
-DskipTests
,不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。-Dmaven.test.skip=true
,不执行测试用例,也不编译测试用例类。
install
1 | mvn install -Dmaven.test.skip=true |
package
同理,打包时也可以跳过1
mvn clean package -Dmaven.test.skip=true -f directory\pom.xml
Maven 引入本地 jar 包依赖
1 | <dependency> |
api 不支持 301 跳转
设置了 301 或 302 跳转的域名,不支持 api 调用。
spring boot @PathVariable 传递带小数点的参数
spring boot 项目,RequestMapping 路由中,在最后一个斜杠后的部分,小数点后面的部分会被忽略掉。
这种处理方式带来的好处:可以做伪静态,将网站的链接都写成 .html,但是实际上,我们的路由可以没有 .html 后缀,这样爬虫在爬网站的时候会当成静态?(没研究是不是这样)
带来的坏处:在通过 uri 传递参数的时候,如果有小数点,其后面的部分会被丢掉,导致程序获取到的参数不正确。不过,这种需求是可以解决的。
解决通过 uri 传递参数不受以上规则影响
其实很简单,就是在路由配置上,在最后加上一个反斜杠就行了,这样,如果输入 url 访问的时候,没有反斜杠,会被当成不存在,这样一来,url 中的参数信息不会被截取。1
2
3
4
5
6
7
public class TController {
"variable/{username}/{password}/") (
public String hello(@PathVariable String username, @PathVariable String password) {
return "username:" + username + "<br>" + "password:" + password;
}
}
访问1
http://localhost:83/variable/andy/fkd.242j8.fdsja&*f7/
将会在页面上输出:1
2userName:andy
passWord:fkd.242j8.fdsja&*f7
如果访问1
http://localhost:83/variable/andy/fkd.242j8.fdsja&*f7
将会得到错误提示,如果网站配置了 404 页面,则会跳转至 404 页面。1
2
3
4
5
6Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Aug 07 08:40:16 CST 2018
There was an unexpected error (type=Not Found, status=404).
No message available
Application failed to start with classpath
这个错误,通常是因为 application.yml 配置有误导致,用排除法解决,就是删除某一顶配置,再启动,如果问题依旧,再删除一项,直到可以正常启动,那么,能正常启动之前删除的配置项,一定是有问题的,修改好了,再恢复之前的配置,如此反复测试,就能找到所有配置有误的地方。
通常,在接手一个旧项目,将期改造,或者用一个开源项目的时候会遇到这种问题。
依赖不能正常下载
到项目根目录,执行 mvn compile
,看报错信息就能知道原因了。
比如我遇到的一次,是 pom.xml 文件在删除 parent 节点的时候,将内部节点 groupId 和 version 一并删除了,就遇到了这个问题。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[INFO] Scanning for projects...
[ERROR] [ERROR] Some problems were encountered while processing the POMs:
[FATAL] 'groupId' is missing. @ line 4, column 109
[FATAL] 'version' is missing. @ line 4, column 109
@
[ERROR] The build could not read 1 project -> [Help 1]
[ERROR]
[ERROR] The project [unknown-group-id]:apg.common.es:[unknown-version] (C:\workspace\source\apg.common\apg.common.es\pom.xml) has 2 errors
[ERROR] 'groupId' is missing. @ line 4, column 109
[ERROR] 'version' is missing. @ line 4, column 109
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectBuildingException
An enum switch case label must be the unqualified name of an enumeration constant
解决:switch case语句case后的枚举常量不带枚举类型
Generating equals/hashCode …
1 | Warning:(5, 1) java: Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type. |
大致意思是默认子类的equals和hashCode方法,不会包含或者考虑基类的属性。
解决
加上注解@EqualsAndHashCode(callSuper=true) ,警告消失。
参考
Information:java: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
在方法前加注解1
@SuppressWarnings("unchecked")
spring boot 项目打包成 war 包发布到 tomcat 窗口,启动时,项目未被加载
1 | <Connector port="8089" protocol="HTTP/1.1" |
单加上上面的,启动时,spring boot 并未被加载,因为我只是改了 pom.xml,加了 <packaging>war</packaging>
,
还需要修改启动类。还需要 extends SpringBootServletInitializer
参考 -> spring boot build as war
jackson 注解
我们在进行数据返回的时候肯定是有些属性不希望前端可以获取到,或者是某些数据为空的时候前端要求不必进行回传,那么这时候我们就可以进行属性的隐藏。
- @JsonIgnore:使用在某个属性上,这样在序列化和反序列化的时候都会忽略这个属性,最直接的效果就是返回的JSON属性是没有这个属性的,一般作用于密码这系列的属性。
- @JsonInclude:使用在某个属性上,配合它的属性Value=JsonInclude.Include.NON_NULL,表示的是如果这个属性的属性值为空那么在返回前端的时候不可见。
- @JsonProperty:使用在某个属性上,这个注解有两个作用,第一是修改返回JSON数据的时候key值为value指定值,第二个作用是配合属性access=JsonProperty.Access.WRITE_ONLY表示属性只可以进行序列化而不能进行反序列化,直观效果就是返回的数据没有该属性。
- @JsonIgnoreProperties:作用在类声明处,它和@JsonIgnore注解的区别就是可以对多个属性作用,直接在value属性后面使用大括号逗号隔开即可,它的ignoreUnknow属性为true表示忽略未定义的属性。
日期:
我们直接使用日期出来的格式必然不是我们想要的,那么我们可以使用注解:@JsonFormat配合上属性pattern标志事件格式,timezone是时区,local是区域。在这里必须强调的是这是把日期格式化为String,一般应用在后台向前端传递数据,如果是前端的String格式需要解析为日期格式我们可以使用@DateTimeFormat即可。@JsonFormat(timezone="GMT+8", pattern="yyy-MM-dd HH:mm:ss")
排序:
有时候为了规范好看我们也需要让属性按照一定顺序进行排列,这时候我们就使用@JsonPropertyOrder这个注解,它的属性alphabetic默认值是false,我们设置为true即可。
以下二者同时用,JsonIgnore 没有生效,返回的 JSON 还是会包含属性。1
2@JsonIgnore
@JsonProperty("毕业院校")
换成:1
@JsonProperty(value="毕业院校", access=JsonProperty.Access.WRITE_ONLY)
同样,JsonIgnoreProperties 与 JsonProperty 同时使用时,前者不会生效。1
2
3
4@JsonIgnoreProperties(value = {"nameSpellAcronym", "sexTxt"})
...
@JsonProperty(value="性别")
private String sexTxt;
关于后端对实体类数据进行格式化输出的方法及使用@JsonSerialize和@JsonFormat
https://www.cnblogs.com/mollie-x/p/10514356.html
关于JSON反序列化与序列化名称问题的一点小经验
https://www.cnblogs.com/yrml/p/9122955.html
- @JsonProperty 这个注解提供了序列化和反序列化过程中该java属性所对应的名称
- @JsonAlias 这个注解只只在反序列化时起作用,指定该java属性可以接受的更多名称
Cannot call sendError() after the response has been committed
导出 excel 时报错:
// 因为在前端请求时,还会有返回,所以,这里如果 close,会导致再次返回时报错:java.lang.IllegalStateException: Cannot call sendError() after the response has been committed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
4822:23:50,843 <org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver> WARN [http-nio-89-exec-4]: Failure while trying to resolve exception [org.springframework.web.HttpMediaTypeNotAcceptableException]
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:472) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.security.web.util.OnCommittedResponseWrapper.sendError(OnCommittedResponseWrapper.java:109) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at com.alibaba.druid.support.http.WebStatFilter$StatHttpServletResponseWrapper.sendError(WebStatFilter.java:343) ~[druid-1.1.16.jar:1.1.16]
at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.handleHttpMediaTypeNotAcceptable(DefaultHandlerExceptionResolver.java:304) ~[spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.doResolveException(DefaultHandlerExceptionResolver.java:181) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:140) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.handler.HandlerExceptionResolverComposite.resolveException(HandlerExceptionResolverComposite.java:79) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:1298) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1110) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1056) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) [spring-webmvc-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-embed-websocket-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103) [spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.21.jar:9.0.21]
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124) [druid-1.1.16.jar:1.1.16]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at mis.api.common.jwt.JwtAuthorizationTokenFilter.doFilterInternal(JwtAuthorizationTokenFilter.java:63) [classes/:?]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) [spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
从提示错误的字面意思判断“Cannotcall sendError() after the response has been committed”,“当response被提交后不能调用sendError()”。
出现这个错误,应该是多次response导致的,可以这么理解,http server发送response后就关闭了socket,这个时候再次发送response给http client就会出现这个问题。
因为 excel 导出,在 return 之前已经 response 处理过流了
invalid source release: 11
1 | Information:java: Errors occurred while compiling module 'mis-config-common' |
- IDEA 的配置路径:Project Structure -> Project -> Project SDK 和 Project language level,把这两项都设置为11就对了。
- 我重新 import 了项目,而 idea 的这两项配置,默认为1.8,而我在每个项目的 pom.xml 配置指定成11了,所以会报这个错。
‘packaging’ with value ‘jar’ is invalid. Aggregator projects require ‘pom’ as packaging.
项目是多模块方式,如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.csist</groupId>
<artifactId>mis-config</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<modules>
<module>mis-config-common</module>
</modules>
</project>
之前没有 <packaging>pom</packaging>
这一项,加上就好了。没有的话,默认是 jar。
mvn compile 时遇到该错误:编码 GBK 的不可映射字符 (0xBB)
解决这个问题的思路: 在maven的编译插件中声明正确的字符集编码编码——编译使用的字符集编码与代码文件使用的字符集编码一致!!
这个是由于代码使用的UTF-8,而maven编译的时候使用的GBK的缘故。 可以通过修改项目的pom文件,可以告诉maven这个项目使用UTF-8编码来编译。在项目的pom.xml文件中,<properties>
节点添加下面的配置:1
2<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
mvn compile 时报错:编码 UTF-8 的不可映射字符 (0xB6)
原因是,支持的 jdk 版本只到 1.8,而 windows 环境变量中设置的版本为 11,切换到 1.8 就好了。修改环境变量之后,记得要把 idea 全部项目关闭,再重新打开新的环境变量才会生效。
或者,在 pom.xml 中指定编译版本也可以。推荐这种方式。
程序包com.sun.xml.internal.messaging.saaj.util不存在
一个老项目,用到 com.sun.xml.internal.messaging.saaj.util
。
解决
1 | <build> |
其中,java.version 需要定义,java.home 不用。另外,IDEA 需要配置一个相应版本(这里是 1.8)的目录才行。1
2
3<properties>
<java.version>1.8</java.version>
</properties>
spring boot 不需要连接数据库配置
spring boot 项目,默认需要注册数据库驱动,但是如果项目不需要数据库支持,在不配置数据库连接信息的情况下,就会报这个错。
解决办法,在@SpringBootApplication注解后面排除数据库自动配置:1
.class,HibernateJpaAutoConfiguration.class}) (exclude={DataSourceAutoConfiguration
如果不加括号里的配置,会报错:Cannot determine embedded database driver class for database type NONE
Caused by: java.lang.NoClassDefFoundError: javax/servlet/ServletContext
上面的错误,是因为我设置了spring-boot编译类型为war,同时设置了tomcat项之后用 IDEA 直接启动 spring-boot,导致内置的tomcat不可用导致的。
1
2
3
4
5<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
其实,把这一项删掉,既不影响在 IDEA 及 Eclipse里调试和运行,也不影响发布到tomcat 容器中运行。
查看thymeleaf默认配置项
在项目中添加下面的引用,按住Ctrl加鼠标查看代码1
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties;
关于 POJO 属性的访问范围修饰符
一开始有部分 POJO 的属性直接用了 public,这样的好处是赋值与取值的代码相对简单。如果需要通过程序赋值,比如通过 MyBatis 查询数据,输出为某 POJO 类型的列表,或者在调用 api 时传入的 JSON 格式。
为了达到程序自动赋值,必须有 setter。这没有问题,只让 IDE 生成 setter 代码就好了,这样还是能让取值代码简洁而“优雅”。这种思想可在 C# 有很好的体现,C# 的 setter 与 getter 就感觉是真的很优雅,C# 不需要定义属性变量,直接定义 getter 与 setter 并且是一个名称,就象在 java 的 POJO 是定义了一个 public 的属性一样。看起来就象是这样:
1
2
3
4
5
6
7
8
9public class RateErrView {
public TopResponse Response { get; set; }
public long BizID { get; set; }
public string SessionKey { get; set; }
public string TID { get; set; }
public string OID { get; set; }
public string From {get;set;}
public string Para {get;set;}
}
但是,问题来了,并不是所有团队成员都明白这个原理,经常出现有因队成员忘记加 setter 的,直到发现数据没有被正确赋值才知道,甚至是,之前添加的属性没问题,只是新加的属性没有被正确赋值,这往往发生在经验尚不足的新同事身上。
再后来,发现有些地方的代码还依赖于 getter,如果能明确哪些 POJO 需要,哪些不需要,也好说,把需要的加上就行了,但是,这个判断并不是每个团队成员都清楚,而且好多这种依赖是随着系统的演进而发生的。
所以,为了避免以上问题,最好的办法就是,不要用 public 的属性,所有属性都是 private 的,而且必须添加 setter 与 getter 代码,让这个规定成为一个不可以破坏的默认约定,这能让项目负责人减少很多不必要的麻烦。
所以,关于 POJO 属性的访问修饰符,规定如下:
- 之前用 public 的保留,新加的一律用 private,private 的属性均需要添加 setter 和 getter。
- 这样能避免某些地方需要 setter 的应用场景不能按预期实现功能,否则可能要到数据异常或者出错时才能发现。
推荐使用 lombok,这样就不需要自己维护 setter 和 getter 了,非常省事儿,配合 IDEA 的 lombok 插件,省心,用上了就离不开了。
关于使用 Map 类型作为参数或者返回值的经验
一开始可以给出一个规则,让团队成员根据规则掌握什么情况能用 Map,什么情况不能用 Map,但是,事与愿违,并不是每个团队成员都能时时刻刻记住和领悟这个规定,总是有人违反规定写出一些不合格的代码。
考虑到,使用 Map 带来的好处要远远小于使用它带来的坏处,何不干脆规定,所有人都不能用它作为参数和返回值呢?
线上环境,.properties 配置中文信息时的注意事项
- 直接通过终端,执行 vi 直接编辑,粘贴中文,再次 vi 或者 cat 看到的是中文信息,那程序读到的将会是乱码。
- 应该在 idea 里编辑好,可以单独新加一个文件,把线上的内容复制下来,修改带有中文信息的配置,然后上传,覆盖线上的文件。这样操作之后,vi 或者 cat 看到的将会是\u开头的字符,这样程序读出来的才是正常的。
- 作为经验教训,建议在配置文件里尽量不要用中文信息。
调用 api 自定义错误信息
实践:返回类型继承 RestApiView1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//返回 RestApiView 的子类
SyncShopView syncShopView = new SyncShopView();
if (syncShopAuthView.getSellerID() == 0L) {
syncShopView.setSuccessOrFail(SuccessOrFailEnum.fail);
syncShopView.setExceptionCodeEnum(ExceptionCodeEnum.notAssignSellerID);
syncShopView.setMessage("同步CRM商家信息:无法获取SellerID,请检查参数的正确性和完整性!");
return syncShopView;
}
//直接返回 RestApiView
RestApiView restApiView = new RestApiView();
SyncRateAuthView syncRateAuthView = JsonHelper.json2Object(requestParametersView.apiParas, SyncRateAuthView.class);
if (syncRateAuthView.getSellerID() == 0L) {
restApiView.setSuccessOrFail(SuccessOrFailEnum.fail);
restApiView.setExceptionCodeEnum(ExceptionCodeEnum.notAssignSellerID);
restApiView.setMessage("同步Rate商家信息:无法获取SellerID,请检查参数的正确性和完整性!");
return restApiView;
}
Diamond types are not supported at this language level
1 | Map<String, Object> paraMapForInit = new HashMap<>(); |
解决办法:
- 中规中矩的把 new HashMap<>() 写成 new HasMap<String, Object>();
- 添加 spring-boot 插件。在 pom.xml 添加下面的内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
添加之后,IDEA 给的建议是:1
2
3Explicit type argument Integer can be replaced with <> less... (Ctrl+F1)
This inspection reports all new expressions with type arguments which can be replaced with diamond type <>
Such <> syntax is not supported under Java 1.6 or earlier JVMs.
这个时候,这样定义即可:1
Map<String, Object> paraMapForInit = new HashMap<>();
java.lang.String cannot be cast to org.springframework.mail.javamail.JavaMailSender
1 | package com.crm.common.application; |
一定要加上:<context:component-scan base-package=”com.crm.common.application”/>
否则,下面的代码1
private static JavaMailSender javaMailSender = (JavaMailSender) BeanTools.getBean(JavaMailSender.class);
会报这样的错:1
java.lang.String cannot be cast to org.springframework.mail.javamail.JavaMailSender
spring boot 执行 jar 报错
1 | [utomcat@192 webapps]$ java -jar web.jar |
之前的打包方式,是在 idea 的 Artifacts 里引入了一个 web 项目,然后 Build Artifacts …
现在,换一种方式1
2
3mvn package
# 直接运行下面的脚本即可,会自动找到 spring boot 的启动类
java -jar web.jar
OK 了。
spring 配置报错:cvc-complex-type.2.1: Element ‘mvc:annotation-driven’ must have no character or element information item [children], because the type’s content type is empty.
在一个比较老的项目里,配置报错:Element mvc:message-converters is not allowed here,没管,直接运行项目,得到:1
Caused by: org.xml.sax.SAXParseException; lineNumber: 81; columnNumber: 29; cvc-complex-type.2.1: Element 'mvc:annotation-driven' must have no character or element information item [children], because the type's content type is empty.
网上一查资料,原来是 Spring 3.1 及以上才支持这种配置方式,这里我用的是 spring 4.3.2,但是 dispatcher-servlet.xml 配置文件里的版本却停留在3.0,如下:1
2
3
4
5
6
7
8
9
10
11
12
13<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
改成,不加版本号的即可解决问题:1
2
3
4
5
6
7
8
9
10
11<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
java 把 gbk 格式的文件,转为 UTF8
https://github.com/downgoon/gbk2utf8
直接提供了工具,下载先来,一条命令全搞定。java -jar gbk2utf8-0.0.1-SNAPSHOT-all.jar $src-gbk-path $dst-utf8-path
而且关键是,如果源目录中既有GBK,又有UTF-8,很多工具最终笼统的对每个文件都 GBK -> UTF-8
,会导致原本就是UTF-8,被误做GBK转码,最后出来的反而是乱码的,这个工具首先识别了源文件是否是GBK,只有是GBK的才转,不是GBK的直接跳过。
view, enumeration 是否要全部放到一个 module 管理?
以 view 为例。
如果放到公共的 view module,这样虽然方便添加和查找,但是如此一来,会增加项目耦合,本来只需要引用一个 module 即可,但是因为这个项目依赖于 view 对应的 module,不得不两个 module 一起引用。
建议:如果 view 并不具有公共性,仅与某个 module 相关,则直接放到此 module,这样其它项目依赖此 module 时,仅依赖这一个 module 即可。
后续:如果某个 view 变得被多个项目依赖,可以考虑将其提取到公共的、专门的 view module。
Jackson Unrecognized field, not marked as ignorable
Jackson是一个可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象的框架。非常方便,同时也很高效。
最近在使用时,将前台传递的JSON 串转成Java实体对象时,出现了Unrecognized field, not marked as ignorable 错误。该错误的意思是说,不能够识别的字段没有标示为可忽略。出现该问题的原因就是JSON中包含了目标Java对象没有的属性。
解决方法有如下几种:
格式化输入内容,保证传入的JSON串不包含目标对象的没有的属性。@JsonIgnoreProperties(ignoreUnknown = true)
在目标对象的类级别上加上该注解,并配置ignoreUnknown = true
,则Jackson在反序列化的时候,会忽略该目标对象不存在的属性。
全局DeserializationFeature配置objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
配置该objectMapper在反序列化时,忽略目标对象没有的属性。凡是使用该objectMapper反序列化时,都会拥有该特性。
Invalid bound statement (not found): express.dal.mapper.original.GwCpInfoMapper.selectByPrimaryKey
1 | <build> |
maven 项目,依赖三方 jar 包,打包项目时自动包含
以下配置,仅开发环境可用,打包时并不能打到 war 和 生意人 lib 目录1
2
3
4
5
6
7<dependency>
<groupId>jd</groupId>
<artifactId>open-api-sdk</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/sdkLib/open-api-sdk-2.0.jar</systemPath>
</dependency>
最终还是需要 mvn install 到本地仓库1
mvn install:install-file -Dfile=open-api-sdk-2.0.jar -DgroupId=jd -DartifactId=open-api-sdk -Dversion=2.0 -Dpackaging=jar
依赖近成这样:1
2
3
4
5<dependency>
<groupId>jd</groupId>
<artifactId>open-api-sdk</artifactId>
<version>2.0</version>
</dependency>
idea每次编译设置工程的默认jdk版本1.5问题
出现这样的原因应该是Maven插件的默认配置有问题。解决方法是在”pom.xml”里加入如下代码:1
2
3
4<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
如果 maven 依赖不能下载,试一下,mvn compile,看看会不会报错,因为有可能是 maven 配置文件有错。
1 | [ERROR] Error executing Maven. |
maven 配置文件时的 1
2
3
4
5
6<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*,!spring-milestones</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
tomcat 下,一个应用程序,发布成两个虚拟目录,该应用配置了 druid 防火墙,会冲突
1 | Caused by: javax.management.InstanceAlreadyExistsException: com.alibaba.druid.wall:name=wall-filter,type=WallFilter |
解决办法:
将配置文件中的这些配置的 ID 改得不一样即可:
WallConfig、WallFilter、StatFilter、DruidDataSource
extend Mapper can't load: Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError
1 | 22:02:03,660 <org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext> WARN [restartedMain]: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'expressHDalServiceImpl' defined in file [C:\workspace\java\shard-test\public.biz\biz.dal\target\classes\biz\dal\shard\service\impl\ExpressHDalServiceImpl.class]: Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError |
这种情况,需要检查 mapper 里的类型是否正确。如下面的:parameterType, type。1
2<resultMap id="BaseResultMap" type="X">
<select id="selectEcodes" parameterType="Y" resultMap="BaseResultMap">
本次遇到的问题,是在用 IDEA 修改包名进行重构的过程中,把 X 和 Y 的 package 路径给去掉了。
导致 spring boot 项目启动报错。
这种错,很难一下子定位到,因为在改 package name 之前一直是运行正常的。
为了排查这个错,将项目 copy 一份,去掉报错的 mapper 之外的所有 mapper,然后去掉里的配置,即 xml 内容,只保留一份从 用 MGB 生成的代码里 copy 过来的简单的,结果启动正常,然后添加一个原有的,结果报错,再仔细看 xml 内容,才发现是类名之前没有加 package 路径,加上就可以了。
获取 xml 配置文件里定义的 bean 信息
1 | ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); |
json-lib:json-lib:jar:2.4
依赖,在 IDEA 的依赖项里面,显示红色下划线,当然,引用其中的类是有问题的。
现象
2.4 版本的依赖引用格式,是在 http://mvnrepository.com/artifact/net.sf.json-lib/json-lib/2.4 找到的,如下:1
2
3
4
5
6<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
</dependency>
- maven 项目,IDEA。pom.xml 文件里显示正常,但引用
net.sf.json
下定义的类时显示红色,即找不到依赖。刷新 maven 依赖,依赖项 json-lib-2.4 显示红色下红线。进入本地 maven 依赖库的下载目录查看,发现下载的是 json-lib-2.4-jdk15.jar,并非预期中的 json-lib-2.4.jar。 - 另外,在一个旧的,非 maven 项目里,引用的是
json-lib-2.4.jar
,引用net.sf.json
下定义的类,正常。
解决方案
度娘了一下,原来通过 Maven 引用时,需要添加 <classifier>jdk15</classifier>
,这应该是 maven 仓库只有基于 jdk1.5 的版本。完整的引用:1
2
3
4
5
6<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
利用反射,实现读取 pojo field 与对应值
以下代码,假设 pojo 的字段均为普通数据类型,即都可以 toString() 显示正确值。1
2
3
4
5
6
7Class reClass = Class.forName("domain.pojoClass");
Field fieldList[] = reClass.getDeclaredFields();
String result;
for (Field field : fieldList) {
System.out.println("ke=" + field.getName() + ", value=" + field.get(outerParameters).toString());
}
类似 isLogin 用 int 类型的数据,如果用 bool 类型数据,用 idea 生成的 getter 会跟变量名一致,容易混淆。
如:1
2
3
4
5
6
7
8
9
10
11public class VerificationRequest {
private boolean isLogin;
public boolean isLogin() {
return isLogin;
}
public void setLogin(boolean login) {
isLogin = login;
}
}
用 int 则清晰自然:1
2
3
4
5
6
7
8
9
10
11public class VerificationRequest {
private int isLogin;
public int getIsLogin() {
return isLogin;
}
public void setIsLogin(int isLogin) {
this.isLogin = isLogin;
}
}
比较时这样用:1
2
3if (verificationCode.getIsLogin() == YesOrNoEnum.yes.getIndex()) {
//some code
}
附 YesOrNoEnum 代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38public enum YesOrNoEnum {
no(0, "否"),
yes(1, "是");
private int index;
private String name;
YesOrNoEnum(int index, String name) {
this.index = index;
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static YesOrNoEnum getEnumByIndex(int index) {
for (YesOrNoEnum result : YesOrNoEnum.values()) {
if (index == result.index) {
return result;
}
}
return null;
}
}
运行 mvn spring-boot:run 之后,再次运行,或者运行 spring boot 的入口程序,端口会冲突
解决:
taskkill /f /t /im java.exe
用 jackson 将数组类型的数据转换成 string 会报错。
1 | 08:33:26,505 <apg.biz.dal.mapper.original.MemberMapper.selectByExample> DEBUG [http-nio-83-exec-2]: <== Total: 0 |
修改 pojo 对应的属性,修改为正确的 List 类型即可。
The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone
在项目代码-数据库连接URL后,加上 (注意大小写必须一致)?serverTimezone=UTC
JAVA对象通过jackson转成json格式,属性名首字母变成小写的解决方法
1 | @JsonProperty //不加此注解的话,返回的字段属性会变成:wxofficialAccount |
package com.sun.xml.internal.messaging.saaj.util does not exist
项目里引用的是 jdk 自带的,位于:C:\dev\Java\jdk1.8.0_161\jre\lib\rt.jar!\com\sun\xml\internal\messaging\saaj\util\Base64.class
在服务器上通过 maven 编译的时候,提示找不到。
解决办法:
添加 Maven 依赖1
2
3
4
5<dependency>
<groupId>com.sun.xml.messaging.saaj</groupId>
<artifactId>saaj-impl</artifactId>
<version>1.4.0</version>
</dependency>
多模板项目,服务器上进入 web 工程 mvn 编译找不到 model
解决:到根目录编译
Spring Boot Application in default package
1 | Spring Boot Application in default package less… (Ctrl+F1) |
是因为把main 函数直接放在了java 目录之下,当放在java目录下的 package目录;
另外官方给出的解决方案是:
@springbootApplication 注解失效的情况下,推荐使用@CompentScan 和@EnableAutoConfiguration进行代替;
Not registered via @EnableConfigurationProperties or marked as Spring component
1 | Not registered via @EnableConfigurationProperties or marked as Spring component less... (Ctrl+F1) |
解决:添加注解 @Component
but snakeyaml was not found on the classpath
1 | Caused by: java.lang.IllegalStateException: Attempted to load applicationConfig: [classpath:/application.yml] but snakeyaml was not found on the classpath |
解决:添加如下依赖即可1
2
3
4<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Loading class `com.mysql.jdbc.Driver’. This is deprecated
1 | database: |
报错信息:1
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
将com.mysql.jdbc.Driver
改为com.mysql.cj.jdbc.Driver
1 | com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support. |
在连接字符串后面加参数serverTimezone=GMT&
由于数据库和系统时区差异所造成的,在jdbc连接的url后面加上serverTimezone=GMT即可解决问题,如果需要使用gmt+8时区,需要写成GMT%2B8,否则会被解析为空。再一个解决办法就是使用低版本的MySQL jdbc驱动,5.1.28不会存在时区的问题。
或者
在[mysqld]
节点在节点下面加上下面这句话1
default-time-zone='+08:00'
Cannot obtain primary key information from the database
1 | Cannot obtain primary key information from the database, generated objects may be incomplete |
https://blog.csdn.net/jpf254/article/details/79571396
pom.xml 的groupId与artifactId,不能有两个相同的
否则,在子项目中,依赖会异常
只要改其中一项即可
Maven项目下HttpServletRequest 或 HttpServletResponse需引用的依赖包
1 | <!-- https://mvnrepository.com/artifact/org.glassfish/javax.servlet --> |
改变自动扫描的包
@ComponentScan(basePackages = {"org.test1","org.test2"})
在启动类中添加了该注解之后,即可扫描org.test2不同包下的注解类了,这里需要注意的是:在修改了自动扫描的包的情况下,默认的自动扫描与启动类同包以及子包下的注解类就不生效了,如果还想要自动扫描与启动类同包以及子包下的注解类的话,就需要手动加上,这里就加上了org.test1
spring boot 以 jar 启动
参考官网getting-started-first-application-run
添加插件
官网是这样描述的:To create an executable jar, we need to add the spring-boot-maven-plugin to our pom.xml. To do so, insert the following lines just below the dependencies section:1
2
3
4
5
6
7
8<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>保存 pom.xml 文件之后,执行打包命令:
mvn clean package -Dmaven.test.skip=true
,如果需要执行单元测试,则直接mvn package
- 将 jar 包上传至服务器,同时把生产环境的配置文件(比如 application.yml)修改好之后放到与 jar 文件相同的目录,运行:
java -jar my-project-0.0.1.jar
,不需要的时候 Ctrl+c 就退出,如果需要一直运行,可设置成开机启动。
注解 @SuppressWarnings({ “rawtypes”, “unchecked” })
java.lang.SuppressWarnings是J2SE 5.0中标准的Annotation之一。可以标注在类、字段、方法、参数、构造方法,以及局部变量上。作用:告诉编译器忽略指定的警告,不用在编译完成后出现警告信息。
PropertiesLoaderUtils.loadAllProperties(“common.properties”);
通过 PropertiesLoaderUtils.loadAllProperties
加载配置文件,配置文件 common.properties
,需要放到启动项目的 resources
目录下,否则项目上线到生产环境,将同名文件放到 /WEB-INF/classes/
目录下,达不到覆盖的目的。
todo: 研究一下读取文件的目录顺序
jackson解析时间
1 | com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2019-06-29 17:25": not a valid representation (error: Failed to parse Date value '2019-06-29 17:25': Cannot parse date "2019-06-29 17:25": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null)) |
将日期转换成时间戳再传递
自定义jackson解析时间格式yyy-MM-dd HH:mm:ss
https://my.oschina.net/xpx/blog/1924695
SpringBoot中后台无法接受前台日期字符串 yyyy-MM-dd HH:mm:ss
https://my.oschina.net/u/3694704/blog/2243415
package org.jetbrains.annotations does not exist
1 | ERROR] COMPILATION ERROR : |
原因
代码里用了 jetbrains.annotations.NotNull
注解,虽然在 IDEA 下直接运行没问题,但到了服务器上就会报上面的错误。
解决
要么引入依赖,要么删除NotNull注解。
java.lang.IllegalArgumentException: The maximum column width for an individual cell is 255 characters.
该异常发生在用 POI 库导出 excel 的过程中,根据内容动态设置 excel 列的宽度 sheet.autoSizeColumn(i)
,内容较多时,宽度会超出 excel 的最大限制。
原代码如下:1
2
3
4
5
6for (int i = 0; i < cnFields.length; i++) {
sheet.autoSizeColumn(i);
// 解决自动设置列宽时,内容含中文时,列宽依然不足,所以,要再加宽一点。
int width = sheet.getColumnWidth(i) * 12 / 10;
sheet.setColumnWidth(i, width);
}
解决
其实,excel 的宽度,设置为60就已经挺宽的了,所以,即使内容较多,也不建议把表格宽度值设置得太大,修后的代码,表格宽度最大60,如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14for (int i = 0; i < cnFields.length; i++) {
sheet.autoSizeColumn(i);
// 解决自动设置列宽时,内容含中文时,列宽依然不足,所以,要再加宽一点。
int width = sheet.getColumnWidth(i) * 12 / 10;
// java.lang.IllegalArgumentException: The maximum column width for an individual cell is 255 characters.
int maxExcelRowWidth = 60;
if (width > maxExcelRowWidth * 256) {
width = maxExcelRowWidth * 256;
}
sheet.setColumnWidth(i, width);
}
java 生成多级目录
file.mkdir() 在创建多级目录时会报错,只支持在存在的目录下创建一级子目录。1
2
3
4
5
6
7File file = new File(filePath);
if (!file.exists() || !file.isDirectory()) {
if (!file.mkdirs()) {
throw new Exception("创建文件夹失败,请联系管理员");
}
}