黑马天机学堂实战问题

配置

IDEA:2024.03
JDK:11
虚拟机:VMware® Workstation 17 Pro

Day01 初识项目

配置本机 host

在 Windows 系统中,你可以通过修改系统的 hosts 文件来实现域名到虚拟机 IP 地址和端口的映射。这是一个简单的操作,不需要任何第三方软件。以下是详细步骤:

步骤 1: 打开 Hosts 文件

  1. 打开记事本程序(Notepad)。

  2. 在记事本中,选择 “文件” > “打开”,或者直接按快捷键 Ctrl + O

  3. 在打开对话框中,输入 C:\Windows\System32\drivers\etc\hosts,然后点击 “打开” 按钮。

    • 注意:你可能需要管理员权限来编辑这个文件。如果系统提示,选择 “是” 以允许对文件进行更改。

步骤 2: 添加域名映射

在打开的 hosts 文件中,添加一行新的文本,格式如下:

`192.168.150.101 yourdomain.com

  • yourdomain.com 替换为你想要映射的域名。

步骤 3: 刷新 DNS 缓存(可选)

为了确保你的更改立即生效,可以刷新 DNS 缓存。打开命令提示符(以管理员身份运行),然后输入以下命令:

ipconfig /flushdns

按回车键执行命令。

文件权限配置

在 jenkins 运行某个微服务时(例如 tj-gateway),会构建失败

Started by user [huge](http://jenkins.tianji.com/user/root)
Running as SYSTEM
Building in workspace /var/jenkins_home/workspace/tj-gateway
[tj-gateway] $ /bin/sh -xe /tmp/jenkins11280295088725351975.sh
+ ssh root@192.168.150.101 /usr/local/src/script/startup.sh -c tj-gateway -n tj-gateway -d tj-gateway -p 10010
copy xx.jar from /usr/local/src/jenkins/workspace/tjxt-dev-build/tj-gateway
cp: cannot stat '/usr/local/src/jenkins/workspace/tjxt-dev-build/tj-gateway/target/tj-gateway.jar': No such file or directory
Build step 'Execute shell' marked build as failure
Finished: FAILURE

观察上面的错误,构建过程是在读取 gateway.jar 时失败的,在虚拟机查看相应目录的权限:
![[综合/Work/笔记/Java路线/attachments/Java 项目.png|377]]

src 目录没有读取权限,使用 chmod src 777 后即可构建成功。

项目本地部署
整个项目 install 出错,找不到符号 log

![[Java 项目-2.png]]

更改 JDK 的版本为 11

IDEA 本地部署报错

![[Java 项目-1.png]]

更改 JDK 版本为 11 后,整个项目构建过程中 tj-course 报错,但 tj-exam 不报错:

[WARNING] The POM for com.alibaba:druid:jar:1.2.6 is invalid, transitive dependencies (if any) will not be available: 2 problems were encountered while building the effective model for com.alibaba:druid:1.2.6
[ERROR] 'dependencies.dependency.systemPath' for com.sun:tools:jar must specify an absolute path but is ${project.basedir}/lib/openjdk-1.8-tools.jar @ 
[ERROR] 'dependencies.dependency.systemPath' for com.sun:jconsole:jar must specify an absolute path but is ${project.basedir}/lib/openjdk-1.8-jconsole.jar @ 

但是项目显示构建成功

[INFO] tj-course .......................................... SUCCESS [ 16.096 s]

此时添加排除依赖后 ExamApplication 可以正常运行(需要先把 JDK 版本改为 11!!!

<dependency>  
    <artifactId>seata-spring-boot-starter</artifactId>  
    <groupId>io.seata</groupId>  
    <version>${seata-version}</version>  
    <exclusions>       
    	<exclusion>           
    		 <groupId>com.sun</groupId>  
            <artifactId>tools</artifactId>  
        </exclusion>        
        <exclusion>            
        	<groupId>com.sun</groupId>  
          	<artifactId>jconsole</artifactId>  
        </exclusion>    
	</exclusions>
</dependency>
修改 NACOS 实例权重或者对某实例下线报错

在 Nacos 控制台进行上述操作,错误信息

caused: errCode: 500, errMsg: do metadata operation failed ;caused: com.alibaba.nacos.consistency.exception.ConsistencyException: 
The Raft Group [naming_instance_metadata] did not find the Leader node;caused: The Raft Group [naming_instance_metadata] did not
find the Leader node;

原因:Nacos 采用 raft 算法来计算 Leader, 并且会记录上次启动的集群地址,所以当我们自己的服务器 IP 改变时(网络环境不稳定,如 WIFI,IP 地址也经常变化),导致 raft 记录的集群地址失效,导致选 Leader 出现问题,
解决方法:删除 Nacos 根目录下 data 文件夹下的 protocol 文件夹,重启 nacos 即可

#相关命令
#进入nacos容器
docker exec -it nacos /bin/bash
#进入nacos的data文件
cd data
#删除protocol文件夹
rm -rf protocol/
#退出容器
exit
#重启nacos容器
docker restart nacos
电脑重启后无法访问虚拟机地址

重启网络和 Docker

systemctl restart networking
sudo systemctl restart docker

然后可以通过 ip+port 访问到 nacos,jenkins 等等,host 文件配置也正确,但就是用域名无法访问,后面重启了 nginx 就行了

sudo systemctl restart nginx

可能是因为 DNS 缓存或者端口冲突问题,重启都能解决

Day02 我的课表

IDEA 配置 MybatisPlus 生成代码

教程上在 Other 下进行配置:
在这里插入图片描述

IDEA 更新后,在 Tools 下配置:
在这里插入图片描述

MyBatis-Plus 的批量插入方法 saveBatch()

在实现添加课程到课表时,在获取到相应的课表信息后,使用 saveBatch() 方法批量新增数据

saveBatch(list);

在这个过程中并没有调用 Mapper 层的方法,其实现原理如下:

在 MyBatis-Plus 中,saveBatch() 方法是一个批量插入操作,它能知道要保存到哪个数据表,主要依赖于以下几个方面:

1. **实体类的映射信息**
    - 每个实体类通常会通过注解(例如 @TableName)或配置来指定对应的数据库表名,以及各个字段与数据库列之间的映射关系。
    - 当你调用 saveBatch() 并传入一个实体列表时,框架会通过反射读取这些元数据,从而确定目标数据表及列信息。
2. **Mapper 与 Service 的绑定**
    - MyBatis-Plus 的 ServiceImpl 类内部会注入 BaseMapper,该 Mapper 是针对特定实体类生成的。BaseMapper 内部包含了自动生成的 CRUD 操作,保存操作自然会使用该实体对应的表信息。
    - saveBatch() 实际上就是调用 BaseMapper 的批量插入方法,利用实体类的元数据生成相应的 INSERT 语句。
3. **底层实现**
    - 底层通过反射和 SQL 生成器,MyBatis-Plus 根据实体类上的注解和配置构造出完整的 INSERT SQL。
    - 然后利用 MyBatis 的批量执行器(Batch Executor)将多条 INSERT 语句一起执行,以提高性能和减少数据库交互次数。

总的来说,saveBatch() 方法之所以能知道保存到哪个表,完全依赖于实体类的映射信息和框架自动生成的 Mapper 配置。这样做不仅简化了批量插入的流程,还减少了手写 SQL 和出错的风险,同时也便于维护和扩展。
添加课程到课表本地测试

服务启动后,在控制台一直没有显示 MQ 发送的消息,然后查看请求的接口
在这里插入图片描述

且报错 服务不存在
根据 api 分析出请求的是 tj-trade 服务,重新打开即可(之前测试时忘记重新打开了)

然后在数据库中更改《Java 泛型》课程的截至报名时间后即可报名成功!

从课表删除课程

删除课程上使用 QueryMapper 报错 String is not a functional interface

int count = lessonMapper.delete(new QueryWrapper<LearningLesson>()  
            .eq(LearningLesson::getUserId, userId)  
            .in(LearningLesson::getCourseId, courseIds));

因为前面创建对象的时候使用的是 QueryWrapper 但是你在使用用却使用了 lambda 表达式,他就会把表达式识别为字符串 (就会提示字符串不是一个功能接口)。

QueryMapper 改为 LambdaQueryWrapper 即可。

Day03 学习计划和进度

Spring Task 定时任务

这里有一个需求是:编写一个 Spring Task 定时任务,定期检查 learning_lesson 表中的课程是否过期,如果过期则将课程状态修改为已过期。

  • LearningApplication 加上 @EnableScheduling 开启定时任务功能
  • 在具体的定时任务函数上加上 @Scheduled 并配置 cron 表达式即可

Spring Task 的缺点:

  • 默认单线程执行
  • 默认不支持分布式(使用持分布式的定时任务调度框架,比如 Quartz、XXL-Job 等)

Day05 问答系统

Spring 启动报错循环依赖

启动 LearningApplication 报错(创建许多 bean 时):

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'interactionQuestionAdminController' defined in file [D:\Workspace\SpringProject\tianji\tj-learning\target\classes\com\tianji\learning\controller\InteractionQuestionAdminController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.

UnsatisfiedDependencyException: Error creating bean with name 'interactionQuestionServiceImpl' defined in file [D:\Workspace\SpringProject\tianji\tj-learning\target\classes\com\tianji\learning\service\impl\InteractionQuestionServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.

UnsatisfiedDependencyException: Error creating bean with name 'interactionReplyServiceImpl' defined in file [D:\Workspace\SpringProject\tianji\tj-learning\target\classes\com\tianji\learning\service\impl\InteractionReplyServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'interactionQuestionServiceImpl': Requested bean is currently in creation: Is there an unresolvable circular reference

根据报错分析,是使用了循环依赖,导致了创建 bean 时发生错误。
定位 InteractionQuestionServiceImplInteractionReplyServiceImpl

public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {  
  
    private final IInteractionReplyService replyService;
    ...
}

public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {  
  
    private final IInteractionQuestionService questionService;
    ...
}

观察到,上面两个 Service bean 循环依赖,导致运行失败,把 IInteractionQuestionService 修改为 InteractionQuestionMapper 即可运行成功。

用户端查询报错

控制台报错如下:

ERROR 27080 --- [nio-8090-exec-5] c.t.c.a.m.advice.CommonExceptionAdvice : 其他异常 uri : /questions/page -> org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.tianji.common.domain.dto.PageDTO<com.tianji.learning.domain.vo.QuestionVO> com.tianji.learning.controller.InteractionQuestionController.queryQuestions (com.tianji.learning.domain.query.QuestionPageQuery) at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters (RequestResponseBodyMethodProcessor.java:163)

代码为

@ApiOperation("用户端分页查询")
@GetMapping("/page")
public PageDTO<QuestionVO> queryQuestions(@RequestBody QuestionPageQuery query) {
    return questionService.queryQuestions(query);
}

@RequestBody 注解通常用于处理 POST 请求的请求体。GET 请求一般不包含请求体,因此会导致 “Required request body is missing” 的错误。去掉 @RequestBody 即可。

Day06 点赞系统

我想的是建立点赞和回答、评论等的关系表,这种做法的缺点是耦合度高,每次新增一个需要使用点赞功能的模块,就需要新建点赞关系表。

点没点赞是存储在 Redis 缓存的,只有具体业务的点赞次数会存在数据表中,由业务端维护。

Day08 排行榜

Xxl-Job 执行创建历史榜单表

任务执行失败,报错:

任务触发类型:手动触发 调度机器:172.18.0.6 执行器 - 注册方式:自动注册 执行器 - 地址列表:null 路由策略:轮询 阻塞处理策略:单机串行 任务超时时间:10 失败重试次数:3 >>>>>>>>>>> 触发调度 <<<<<<<<<<< 调度失败:执行器地址为空

执行器地址应该是启动 LearningApplication 后会自动注册,但现在正常启动后没有注册
![[Java 项目-8.png]]
![[Java 项目-10.png|373]]

但在 nacos 上是没问题的
![[Java 项目-9.png]]

本地启动 TradeApplication 后,Xxl-job 中 tarde-service 的注册节点数目也增加到了 2
![[Java 项目-11.png]]

LearningApplication 启动报错:

09:58:54.282-[DESKTOP-RJ5DTTM][sys] - WARN 53124 --- [           main] c.x.j.core.thread.TriggerCallbackThread  : >>>>>>>>>>> xxl-job, executor callback config fail, adminAddresses is null.
09:58:54.284-[DESKTOP-RJ5DTTM][sys] - WARN 53124 --- [           main] c.xxl.job.core.executor.XxlJobExecutor   : >>>>>>>>>>> xxl-job accessToken is empty. To ensure system security, please set the accessToken.
09:58:54.318-[DESKTOP-RJ5DTTM][sys] - INFO 53124 --- [       Thread-9] com.xxl.job.core.server.EmbedServer      : >>>>>>>>>>> xxl-job remoting server start success, nettype = class com.xxl.job.core.server.EmbedServer, port = 9999
09:58:54.320-[DESKTOP-RJ5DTTM][sys] - WARN 53124 --- [       Thread-9] c.x.j.c.thread.ExecutorRegistryThread    : >>>>>>>>>>> xxl-job, executor registry config fail, appname is null.

解决:tj-learning 的 bookstrap.Yaml 没有引入 xxl-job 加入后执行器地址配置成功:

- dataId: shared-xxljob.yaml  
  refresh: false

Day09 优惠券管理

思考:

  1. 优惠券定时发放会设置开始时间和结束时间,例如开始时间设置好了,通过定时任务来修改发放状态,定时任务应该不能设置地太频繁吧?(例如每分钟一次,负载压力会不会很大?)
    现在设置为 10 分钟,不知道实际工程中如何设置
@Transactional 自调用错误
@Override
@Async ("generateExchangeCodeExecutor") 
public void asyncGenerateCode (Coupon coupon) {
	...
	saveBatch (list);
}

报错:

@Transactional 自调用 (实际上是目标对象内的方法调用目标对象的另一个方法) 在运行时不会导致实际的事务

原因:asyncGenerateCode 方法被 @Async 注解标记,这意味着它会在一个单独的线程中异步执行。然而,@Transactional 注解默认情况下不会对异步方法生效,因为异步方法的调用不会通过 Spring 的代理对象,而是直接调用目标对象的方法。

解决方法:使用 @Transactional 的传播属性,改为

@Transactional(propagation = Propagation.REQUIRED)

或者获取当前的动态代理对象,然后调用事务方法。

分页查询优惠券报错

SQL 语句为:

SELECT id, name, type, discount_type, specific, discount_value, threshold_amount, max_discount_amount, obtain_way, issue_begin_time, issue_end_time, term_days, term_begin_time, term_end_time, status, total_num, issue_num, used_num, user_limit, ext_param, create_time, update_time, creater, updater FROM coupon ORDER BY create_time DESC LIMIT 5;

报错:

/* SQL 错误(1064):You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near'specific, discount_value, threshold_amount, max_discount_amount, obtain_way, iss' at line 1 */

把 specific 改为 ` specific ` 就可以了

同时在代码中进行更改即可:

@ApiModelProperty(value = "是否限定作用范围,false:不限定,true:限定。默认false")  
@TableField("`specific`")  
private Boolean specific;

Day10 领取优惠券

Jmeter 打开文件错误
java.lang.NoClassDefFoundError: Could not initialize class org.apache.jmeter.gui.util.FileDialoger ...

Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalAccessError: class com.github.weisj.darklaf.ui.filechooser.DarkFilePaneUIBridge$DetailsTableModel...

把外观改为 window 即可,在暗黑模式下出问题。

参考

  1. 天机学堂踩坑笔记
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值