‹ 返回笔记 Esc·

Java 问题与修复

指定配置和端口 --- 直接命令运行代码 1. 确认项目结构和入口 src/ 里是源码(.java 文件) bin/ 里是编译后的 .class 文件(如果已经编译过) lib/ 里是依赖的 jar …

指定配置和端口

1java -jar -server blog-1.0.jar --spring.profiles.active=prod --server.port=9001

直接命令运行代码

1.
2├── bin
3│   ├── encrypt
4│   │   ├── AesUtil.class
5│   └── test
6│       ├── RestClientFetchData.class
7│       └── TestMain.class
8├── lib
9│   ├── bcprov-jdk15-143.jar
10│   ├── commons-codec-1.3.jar
11│   └── json.jar
12├── src
13│   ├── encrypt
14│   │   ├── AesUtil.java
15│   └── test
16│       ├── RestClientFetchData.java
17│       └── TestMain.java
18└──
  1. 确认项目结构和入口

src/ 里是源码(.java 文件)

bin/ 里是编译后的 .class 文件(如果已经编译过)

lib/ 里是依赖的 jar 包

  1. 编译源码(如果还没编译)

假设你的源码在 src/,目标 class 文件输出到 bin/,可以用如下命令:

1mkdir -p bin
2javac -d bin -cp "lib/*" src/**/*.java
  1. 找到主类(Main class)

主类一般有 public static void main(String[] args) 方法。假设主类叫 com.example.Main,你需要知道它的全限定名(包名+类名)。

  1. 运行项目
1java -cp "bin:lib/*" com.example.Main
  • -cp "bin:lib/*":包含编译输出和依赖
  • com.example.Main:主类的全限定名

注意:在 macOS 或 Linux 下用冒号 : 分隔 classpath,Windows 下用分号 ;

-cp 是 -classpath 的缩写


DTO 类返回从命令从驼峰变成下划线

整个类用 @JsonNaming

1import com.fasterxml.jackson.databind.PropertyNamingStrategies;
2import com.fasterxml.jackson.databind.annotation.JsonNaming;
3
4@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
5public class ExampleDto {
6    // … 字段不变 …
7}

单个字段用 @JsonProperty

1import com.fasterxml.jackson.annotation.JsonProperty;
2
3public class DaypartingCalcResultDto {
4    @JsonProperty("total_use_electricity")
5    private Double totalUseElectricity;
6
7    @JsonProperty("peak_cost")
8    private String peakCost;
9
10    // …其余字段类似…
11}

数据库连接池 HikariCP 对比 Druid

  • 选HikariCP:当项目需要高性能、简单配置,且以性能为核心考量。
  • 选Druid:当项目需要详细监控、SQL优化功能,且愿意接受稍复杂的配置。有控制台

String 类中 empty 和 blank 的区别

1"".isEmpty();         // true
2"   ".isEmpty();      // false(因为有空格)
3null.isEmpty();       // 会抛出 NullPointerException

isEmpty()判断某字段字符串是否为空,为空的标准是 str == null 或者 str.length() == 0

1"".isBlank();         // true
2"   ".isBlank();      // true
3"\n\t".isBlank();     // true
4"abc".isBlank();      // false
5null.isBlank();       // 会抛出 NullPointerException

isBlank()【Java 11+】判断某字符串是否为空或长度为 0 或由空白符、制表符、换行符、换页符、回车符构成

建议用 import org.springframework.util.StringUtils;

!StringUtils.hasLength(str) = isEmpty

!StringUtils.hasText(str) = isBlank


BeanUtils.copyProperties 用法

BeanUtils.copyProperties 可以用于更新,将源数据更新到目标数据中

1import org.springframework.beans.BeanUtils;
2public Result updatePostgraduate(@RequestBody EasPostgraduate easPostgraduate) {
3    EasPostgraduate oldPostgraduate = easPostgraduateService.getById(easPostgraduate.getId());
4    BeanUtils.copyProperties(easPostgraduate, oldPostgraduate); easPostgraduateService.updateById(oldPostgraduate);
5}
6
7// 集合类需要遍历复制
8List<Company> companies = companyMapper.selectList(new QueryWrapper<Company>().lambda().like(name != null
9&& !"".equals(name), Company::getName, name) );
10List<CompanyInfoVO> companyInfo = new ArrayList<>();
11for (Company company : companies) {
12    CompanyInfoVO companyInfoVO = new CompanyInfoVO();
13    BeanUtils.copyProperties(company, companyInfoVO);
14    companyInfo.add(companyInfoVO);
15}

@WebFilter 过滤路径太广

@WebFilter不加任何属性时为过滤全部路径 @WebFilter(urlPatterns = "")加上这个属性之后只过滤指定路径,指定路径在其他地方写


JSONObject 链式添加元素

new JSONObject().fluentPut("code", 400); 且可以直接 new 对象放入在其他 JSONObject 里 jo.put("data", new JSONObject().fluentPut("status", "read"));


JSONArray 转换成 Java 列表

1JSONArray records = respJson.getJSONArray("records");
2List<JSONObject> javaList = records.toJavaList(JSONObject.class);

或者直接

1List<JSONObject> list = respJson.getList("records", JSONObject.class);

使用 JSONObject 和 VO 区别

如果查询的 SQL 返回 null,则 JSONObject 不返回此字段值,VO 则返回字段值 "field" : null


请求参数的限制

参数上写上@RequestParam这个注解,代表参数需要存在默认是(required = true)

参数上什么都不写等于@RequestParam(required = false),就是这个参数不传值就为null

参数上写上@NonNull,参数为不传则直接抛出 NPE 异常,是 Lombok 的注解 建议必传参数用@RequestParam,不必传参数就不写注解


@WebFilter 注解方式不生效

注意filterName不要显示的写类的驼峰命名法,直接去掉会默认以类名驼峰命名法来注入到 bean 中,在Application中加上@ServletComponentScan注解来启动


打印字体输出颜色

System.out.println可以输出一段文本,并且默认的字体颜色是黑色。如果想要把部分文本以红色字体显示,需要使用控制台输出时支持 ANSI 转义序列的终端工具。

1System.out.println("\033\[31m" + "哈哈" + "\033\[0m");

其中,\033\[31m表示设置当前输出文本的颜色为红色, \033\[0m表示重置输出文本的格式,确保之后的文本不会受到前面设置属性的影响。

ANSI 转义序列中的\033\[33m 表示将文本颜色设置为黄色,其中 33 代表颜色代码。具体而言,在 ANSI 颜色编码中,30-37 分别代表黑、红、绿、黄、蓝、紫、青和白。


项目运行立即执行一次任务

1@PostConstruct
2public void executeTask() {}

这将使任务在 Spring 应用程序上下文加载后立即执行一次,并且不会重复执行。请注意,此方法不是传统的基于时间的 cron 表达式方式,而是基于事件的触发器方法,在Spring框架中比较常见。


字段值为 null 不返回此字段

1// 实体类上加 @JsonInclude(JsonInclude.Include.NON_NULL)
2@JsonInclude(JsonInclude.Include.NON_NULL)
3public class SuccessResult extends Result { public Object data; ... }

实体类日期类型格式化

在实体类上增加@JsonFormat注解

1@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
2private LocalDateTime createTime;

@Secured 和 @PreAuthorize 注解的区别

@Secured@PreAuthorize是 Spring Security 框架中用于方法安全性检查的两个注解。它们的主要区别在于安全检查的方式和表达式的使用。

  1. 安全检查方式:
  • @Secured:基于角色和权限进行安全性检查。该注解通过指定一个或多个角色或权限,限制方法的访问。例如,@Secured(“ROLE_ADMIN”)表示只有具有“ROLE_ADMIN”角色的用户才能访问该方法。
  • @PreAuthorize:基于表达式进行安全性检查。该注解使用 Spring Expression Language(SpEL)表达式来定义访问规则。例如,@PreAuthorize(“hasRole(‘ROLE_ADMIN’)”)表示只有具有“ROLE_ADMIN”角色的用户才能访问该方法。
  1. 表达式使用:
  • @Secured:不支持使用表达式,只能直接指定角色或权限。例如,@Secured(“ROLE_USER”)表示只有具有“ROLE_USER”角色的用户才能访问该方法。
  • @PreAuthorize:支持使用Spring Expression Language(SpEL)表达式来进行访问控制。SpEL 是一种强大的表达式语言,可以访问方法参数、方法返回值、作用域对象等。例如,@PreAuthorize(“hasRole(‘ROLE_ADMIN’)”)表示只有具有“ROLE_ADMIN”角色的用户才能访问该方法。

在实际应用中,@PreAuthorize注解通常更为灵活,因为它可以使用表达式来定义复杂的访问规则,如基于多个角色、权限以及其它条件的组合进行访问控制。而@Secured注解则更适用于简单的角色或权限检查场景。


忽略实体类值为null的字段

1List<User> records = pageInfo.getRecords();
2List<JSONObject> list = JSONObject.parseArray(JSON.toJSONString(records), JSONObject.class);
3// 泛型可以变成自己设置的VO类来接收
4List<MemberInfoVO> list = JSONObject.parseArray(JSON.toJSONString(records), MemberInfoVO.class);

Lambda 批量插入数据库写法

1List<String> authoritiesList = wrapper.getJSONArray("authorities").toJavaList(String.class)
2List<UserAuthority> list = new ArrayList<>();
3authoritiesList.forEach(authority -> list.add(new UserAuthority().setUid(uid).setAuthority(authority));

Token 前缀去除

1// 去除token前面的"Bearer "
2token = token.replaceFirst("^\\\S+\\\s", "");

日期字符串解析成 LocalDateTime

1// 格式必须为 2023-01-01T00:00:00 才行 String startDateTimeStr = wrapper.getString("startDateTime");
2LocalDateTime startDateTime = LocalDateTime.parse(startDateTimeStr);
3// 2023-01-01 00:00:00 就不行会报错 要用以下办法
4DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
5LocalDateTime startDateTime = LocalDateTime.parse(startDateTimeStr, formatter);

jar 包增量更新

  1. 将解压后的文件放在一个没有任何其他内容的文件夹中。
  2. 删除原 jar 包,确保当前文件夹中只包含你想要压缩的文件。
  3. 在该文件夹中打开命令行窗口(在文件路径中输入 cmd 即可进入)。
  4. 在命令行中输入jar cvf0M name.jar ./,其中 name 代表你想要的 jar 包的名字,./表示当前文件夹中的所有文件。
  5. 按下回车键,命令行会开始压缩文件,并生成一个新的 jar 包。

Java 命令传递键值对形式的配置

1java -DmyProperty=myValue -jar app.jar

可以使用 System.getProperty("myProperty") 来获取这个属性的值:

1public class Main {
2    public static void main(String[] args) {
3        String myProp = System.getProperty("myProperty");
4        System.out.println("My Property: " + myProp);
5    }
6}

跳过单元测试

点击 Maven 中的禁止图标 Toggle ‘Skip Tests’ Mode


自动装配 mapper 报红线解决方式

1@Autowired(required = false)
2private UserMapper userMapper;
1@Resource
2private UserMapper userMapper;
1@Repository
2// Mapper 接口加上 @Repository 注解
1@RequiredArgsConstructor(onConstructor = @__(@Autowired))
2// Lombok 的注解,使用构造方法注入的方式