一些报错处理
找不到注入的对象
可以在 dao 层 的接口上添加 @Repository 注解
common 模块报错 Unable to find main class
由于common中只有一些常量与工具类,不需要主类,故出现该错误时只需删除pom文件中的build标签即可解决
网关模块报错 Failed to configure a DataSource: ‘url’ attribute is not specified and no embedded datasource could be configured.
原因是没有配置数据库相关信息,然而网关不需要与数据库交互,解决方法是在启动类上修改
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
关闭对数据库配置的自动装配即可
@Value注解获取不到配置值
原因:@Value注解不能给静态变量赋值
解决方法:编写Setter方法代替
private static int port;
private static String username;
/**
* 设置port
*
* @param port port
*/
@Value("${spring.rabbitmq.port}")
public void setPort(int port) {
RabbitMqConnectionFactory.port = port;
}
/**
* 设置username
*
* @param username username
*/
@Value("${spring.rabbitmq.username}")
public void setUsername(String username) {
RabbitMqConnectionFactory.username = username;
}
运行@Test方法时,不能使用Scanner类在控制台输入数据
帮助—编辑自定义虚拟机选项,追加以下配置,重启Idea即可(help — Edit Custom VM Options)
-Deditable.java.test.console=true
运维过程中发现数据输入错误
某标准字段因误输入多了个空格,导致多个表数据错误,现要用sql语句修正该字段数据,如何在数据库中找到所有错误数据并修正呢?(Oracle数据库)
SELECT
'UPDATE ' || TABLE_NAME || ' SET ' || COLUMN_NAME || ' = ''正确数据值'' WHERE ' || COLUMN_NAME || ' = ''错误数据值'';'
FROM ALL_TAB_COLUMNS
WHERE COLUMN_NAME = '列名' # COLUMN_NAME like '%模糊查找列名%'
AND OWNER = '数据库名'
执行该语句后会自动生成更新语句,复制粘贴到执行面板,检查后执行即可
软删除和唯一约束冲突
数据库规范要求,业务上唯一的字段必须在数据库中建立约束,但是又想记录被删除的数据,做软删除,这就导致了删除了的数据会与未删除的数据发生冲突。
解决方案是将软删除加入唯一键列,例如,设置username和isdeleted为联合唯一,然后删除数据时将isdeleted赋值为主键,MyBatis的实现方法如下:
/**
* 删除标记
*/
@TableLogic(value = "0", delval = "id")
@TableField(fill = FieldFill.INSERT)
protected Integer isDeleted;
hutool CollUtil 取交集,并集和差集
有个需求,实现班级学生的调整
其实挺简单的,点击确定时候调用接口把该班级之前存储的学生删除,再把当前选中的学生存起来就行。但是因为用的是软删除,每次调整学生班级的时候,数据表里会多出好多没用的数据。
这里使用 hutool
的 CollUtil
进行集合操作,分开处理重复的数据与新增的数据。
CollUtil.intersection
取交集
CollUtil.subtract
取差集
CollUtil.disjunction
取交集的补集
CollUtil.union
取并集
具体实现如下
// 重复的(不需要操作的)
List<Long> repeatList = new ArrayList<>(CollUtil.intersection(新学生列表, 原学生列表));
if (!repeatList.equals(原学生列表)) {
// 要删除的
List<Long> deleteList = new ArrayList<>(CollUtil.subtract(原学生列表, repeatList));
LambdaQueryWrapper<GradeStudentEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(GradeStudentEntity::getGradeId, vo.getGradeId());
if (ObjectUtil.isNotEmpty(deleteList)) {
wrapper.in(GradeStudentEntity::getStudentId, deleteList);
}
remove(wrapper);
}
// 要新增的
List<Long> addList = new ArrayList<>(CollUtil.subtract(新学生列表, 原学生列表));
if (!addList.isEmpty()) {
List<GradeStudentEntity> list = new ArrayList<>();
for (Long studentId : addList) {
GradeStudentEntity entity = new GradeStudentEntity();
entity.setStudentId(studentId);
entity.setGradeId(vo.getGradeId());
list.add(entity);
}
saveBatch(list);
}
MyBatis 一对多映射
主子表的关系,想要一条sql查出来
mapper.xml如下
<resultMap type="com.power.milk.vo.MilksetVO" id="milkSetVoMap">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="price" column="price"/>
<result property="image" column="image"/>
<result property="description" column="description"/>
<result property="status" column="status"/>
<collection property="flavorItems" ofType="com.power.milk.vo.MilkFlavorVO">
<result property="id" column="f_id"/>
<result property="name" column="f_name"/>
<result property="description" column="f_description"/>
<result property="number" column="f_number"/>
</collection>
</resultMap>
<select id="getList" resultMap="milkSetVoMap">
select m.* ,
j.name AS CategoryName,
mf.id as f_id,
mf.name as f_name,
mf.description as f_description,
mf.number as f_number
from milkset m
left join milk_flavor mf on mf.milk_or_set = 2
and mf.milk_or_set_id = m.id and mf.is_deleted = 0
where m.is_deleted = 0
</select>
然后再写下 MilksetVO 类
package com.power.milk.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.power.milk.common.utils.DateUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* 套餐
*
* @author Power
* @since 2024-04-10
*/
@Data
@ApiModel(description = "套餐")
public class MilksetVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@ApiModelProperty(value = "牛奶分类id")
@JsonSerialize(using = ToStringSerializer.class)
private Long categoryId;
@ApiModelProperty(value = "套餐名称")
private String name;
@ApiModelProperty(value = "套餐价格")
private BigDecimal price;
@ApiModelProperty(value = "图片")
private String image;
@ApiModelProperty(value = "套餐明细Json文本")
private String flavorItemsJson;
@ApiModelProperty(value = "套餐明细")
private List<FlavorInMilk> flavorItems = new ArrayList<>();
}
en…可能不太规范,但是确实实现了
Spring Boot 运行单元测试时使用不同配置文件
学习RabbitMQ的时候要跑官网的例子,又不想写好几个项目跑,就直接在SpringBoot的项目里加了测试类,由于每个例子的配置又不太一样,就学习了下怎么指定配置文件运行单元测试
举个例子,下边这段是 fanout 模式的代码
package com.gettler.rabbitmq.fanout;
import com.gettler.rabbitmq.RabbitmqApplication;
import com.gettler.rabbitmq.config.RabbitMqConnectionFactory;
import com.rabbitmq.client.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
@ActiveProfiles("fanout")
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RabbitmqApplication.class, webEnvironment =
SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ConsumerATest {
private static final Logger logger = LoggerFactory.getLogger(ConsumerATest.class);
@Test
public void testConsumerA() throws Exception {
// 创建一个connection
Connection connection = RabbitMqConnectionFactory.getSingleInstanceConnection();
// 创建一个channel
Channel channel = connection.createChannel();
// 声明交换机
channel.exchangeDeclare("fanout", BuiltinExchangeType.FANOUT);
// 声明临时队列
String queueName = channel.queueDeclare().getQueue();
// 绑定队列与交换机
channel.queueBind(queueName, "fanout", "");
// 消费消息
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("获得消息:" + new String(message.getBody()));
};
CancelCallback cancelCallback = (consumerTag) -> {
System.out.println("消息消费被中断");
};
channel.basicConsume(queueName, true, deliverCallback, cancelCallback);
}
}
@ActiveProfiles("fanout")
就是指定读取 fanout
配置文件
这样就可以读取到其他配置文件了