1)对象属性拷贝:
前提条件是两个类中的属性名称要相同,属性个数可以不同,使用org.Springframework.beans
中的BeanUtils
工具类,调用内部的copyProgects
方法,次方法第一个参数表示要拷贝的类,第一个参数表示要拷贝到的类
ag: 将addEmployeeDTO
类中的属性拷贝到employee
类中
java
// 对象属性拷贝
BeanUtils.copyProperties(addEmployeeDTO,employee);
2)MD5加密:
将密码存入数据库时一般进行加密,这里使用org.Springframework.util
中的md5DigestAsHex
方法,参数为字节数组
ag:将字符串密码1234进行加密
java
// 设置密码(默认密码)
employee.setPassword(DigestUtils.md5DigestAsHex("1234".getBytes(StandardCharsets.UTF_8)));
3)ThreadLocal:
threadLocal并不是一个线程,二是thread的局部变量,ThreadLocal
为每一个线程单独提供一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外择不能访问(每一次请求就是一个单独的线程)
ThreadLocal常用方法:
-
public void set(T value)
:设置当前线程的线程局部变量的值 -
Public T get()
:返回当前线程对应的线程局部变量的值 -
public void remove()
:移除当前线程的线程局部变量
java
/**
* ThreadLocal工具类
*/
public class BaseContext {
// 创建一个ThreadLocal的对象
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
// 定义一个方法调用ThreadLocal内部的set方法
public static void setCurrentId(Long id) {
threadLocal.set(id);
}
// 定义一个方法调用ThreadLocal内部的get方法
public static Long getCurrentId() {
return threadLocal.get();
}
// 定义一个方法调用ThreadLocal内部的remove方法
public static void removeCurrentId() {
threadLocal.remove();
}
}
4)使用pageHelper简化分页查询:
引入依赖:
java
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>版本号</version>
</dependency>
调用PageHelper
中的startPage
方法进行分页:
java
// 参数1:表示页数
// 参数2:表示每页的记录数
PageHelper.startPage(参数1,参数2);
如果分页查询还有其它选项,就可以单独编写sql语句,但返回的结果必须为PageHelpe
r包下的Page
类型,范型为对应的实体:
eg:
java
public PageResult selectEmployeePageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
// 开始分页查询
PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());
// 分页查询的基础上添加姓名的模糊查询
Page<Employee> page = employeeMapper.selectPage(employeePageQueryDTO);
// 获取page中的数据转换为PageResult结果
long total = page.getTotal(); // 获取中的记录数
List<Employee> result = page.getResult(); // 获取查询到的结果
return new PageResult(total,result);
}
对应的映射文件中就可以直接编写拼接的sql:
java
<select id="selectPage" resultType="com.sky.entity.Employee">
select * from employee
<where>
<if test="name != null and name != ''">
and name like concat('%',#{name},'%')
</if>
</where>
</select>
5)处理后端响应前端时的LocalDateTime时间格式问题:
**方法一:**在对应的实体类中的LocalDateTime类型的数据上添加@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")注解
java
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
方法二: 扩展springMVC的消息转换器,创建类继承WebMvcConfigurationSupport
类重写内部的extendMessageConverters
方法
java
/**
* 扩展spring MVC的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// 创建一个消息转换器对象
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
// 设置对象转换器,可以将Java对象转换为json字符串
mappingJackson2HttpMessageConverter.setObjectMapper(new 消息转换器类对象);
// 将自己的转换器对象放入spring MVC框架中
converters.add(0,mappingJackson2HttpMessageConverter);
}
对象转换器类:
java
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
//public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
**注意:**方法二继承的类与Swagger继承的类相同
6)公共字段自动填充
数据库中多张表中都有重复字段时,可以使用公共字段填充,减少开发中代码的冗余
实现思路:
-
自定义注解AutoFill,用于标识需要进行公共字段自动填充的方法
-
自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法,通过反射为公共字段赋值
-
在Mapper的方法上加入AutoFill的注解
eg:
自定义注解:
java
/**
* 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
*/
@Target(ElementType.METHOD) // target标识该注解加入的位置,这里设置只能添加到方法上
@Retention(RetentionPolicy.RUNTIME) // 用于指定注解的保留策略。RetentionPolicy.RUNTIME 表示该注解在运行时仍然可用。
public @interface AutoFill {
// 使用枚举标,识数据库操作类型
OperationType value();
}
枚举类实现:
java
/**
* 数据库操作类型
*/
public enum OperationType {
// 更新操作
UPDATE,
// 插入操作
INSERT
}
自定义切面类:
java
/**
* 自定义切面类,实现公共字段自动填充的处理逻辑
*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
/**
* 定义切入点
*/
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
public void autoFillPointCut(){}
/**
* 前置通知,在通知中进行公共字段的赋值
*/
@Before("autoFillPointCut()")
public void autofill(JoinPoint joinPoint){
log.info("开始公共字段自动填充···");
// 获取当前被拦截的方法上的数据库的操作类型
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 获取被拦截方法的签名对象
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); // 获取方法上的注解对象
OperationType operationType = autoFill.value(); // 获取数据库操作类型
// 获取当前被拦截的方法的参数--实体对象
Object[] args = joinPoint.getArgs(); // 获取所有的参数
// 判断获取的参数是否为空
if (args == null || args.length == 0){
return;
}
// 获取实体类对象
Object entity = args[0];
// 准备赋值的数据
LocalDateTime nowTime = LocalDateTime.now(); // 当前时间
Long currentId = BaseContext.getCurrentId(); // 获取当前用户ID
// 根据当前不同的操作类型,为对应的属性通过反射进行赋值
if(operationType == OperationType.INSERT){
// 获取对应实体类中的set方法进行赋值
try {
Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
// 通过反射进行赋值
setCreateTime.invoke(entity,nowTime);
setCreateUser.invoke(entity,currentId);
setUpdateTime.invoke(entity,nowTime);
setUpdateUser.invoke(entity,currentId);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else if (operationType == OperationType.UPDATE) {
// 获取对应实体类中的set方法进行赋值
try {
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
// 通过反射进行赋值
setUpdateTime.invoke(entity,nowTime);
setUpdateUser.invoke(entity,currentId);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}