Arrays工具类
使用Arrays.sort( )对自定义类进行排序的时候,这个类需要实现(implements) Comparable<类名>,然后重写compareTo( )这个方法。
Lambda表达式
Lambda表达式,必须要有一个接口类,并且这个接口类中只有有一个抽象方法,注意:不能是抽象类,只能是接口。
(重写方法的参数列表)->{
重写方法的代码
};
Lambda简化
(o1,o2)->{
重写方法的代码
};
(o1,o2)-> 重写方法的代码;
Mybatis常用标签
<update id="update" parameterType="Category">
parameterType
:通过mapper传递过来的参数类型。
<select id="list" resultType="Category">
resultType
:MyBatis会根据SQL语句的结果集中的列名与resultType
类型的属性进行自动映射,将每一行数据转换为一个resultType
实例。
<insert id="insertBatch" useGeneratedKeys="true" keyProperty="id">
insert into dish_flavor(dish_id, name, value) values
<foreach collection="flavors" item="df" separator=",">
(#{df.dishId},#{df.name},#{df.value})
</foreach
</insert>
useGenerateKeys
:这是一个属性设置,表示开启JDBC的getGeneratedKeys功能来获取数据库自动生成的主键值。许多数据库系统(如MySQL、SQL Server等)支持在插入数据时自动为某些列生成唯一标识符(通常是主键)。通过设置useGeneratedKeys="true"
,MyBatis可以将这些自动生成的主键值映射到实体对象中。
keyProperty
:指定主键为谁。
@Transactional
public void saveWithFlavor(DishDTO dishDTO) {
Dish dish = new Dish();
BeanUtils.copyProperties(dishDTO,dish);
//向菜品表添加数据
dishMapper.insert(dish);
//获取dishId
long dishId=dish.getId();
//向口味表插入n条数据
List<DishFlavor> flavors=dishDTO.getFlavors();
if(flavors!=null&& flavors.size()>0){
flavors.forEach(dishFlavor -> {
dishFlavor.setDishId(dishId);
});
//非空数据
dishFlavorMapper.insertBatch(flavors);//保持一致,都为flavors
}
}
collection
:通常是传递过来一个集合,collection的值和传递过来的值保持一致。
item
:依次遍历collection这个集合,每一次遍历出来的对象叫做item
。
separator
:一次遍历完了之后和下一次遍历的结果之间的分隔符
Mybatis配置文件
mybatis:
#mapper配置文件
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.sky.entity #设置别名
configuration:
#开启驼峰命名
map-underscore-to-camel-case: true
PageHelper
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
//设置当前的页码是多少,以及当前页面有多少个数据
PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());
//查询结果封装在Page中
Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
//获取查询到的所有的数据数量
long total=page.getTotal();
//拿到分页查询的数据
List<Employee> records=page.getResult();
//返回PageResult
return new PageResult(total,records);
}
AOP切面操作
切面操作通常用来简化代码。
依赖:
<dependencies>
<!--spring核心依赖,会将spring-aop传递进来-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--切入点表达式依赖,目的是找到切入点方法,也就是找到要增强的方法-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
- 在Spring配置类上打开注解,开启注解开发AOP功能—>
@EnableAspectJAutoProxy
。 - 定义通知类,制作通知方法。通知类必须配置为Spring管理的bean
- 定义切入点表达式、配置切面(绑定切入点与通知关系)
//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类
@Aspect
public class MyAdvice {
//设置切入点,@Pointcut注解要求配置在方法上方
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
//设置在切入点pt()的前面运行当前操作(前置通知)
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
Annotation自定义注解
public enum OperationType {
//更新操作
UPDATE,
//插入操作
INSERT
}
@Target(ElementType.METHOD) //注解只能加在方法上
@Retention(RetentionPolicy.RUNTIME) //注解在运行期间起作用
public @interface AutoFill {
//数据库操作类型:update insert
OperationType value();
}
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
//切入点
//锁定com.sky.mapper包下的所有类的所有方法,并且标注了AutoFill这个注解的方法就会被拦截进行填充处理
@Pointcut("execution(* com.sky.mapper.*.*(..))&&@annotation(com.sky.annotation.AutoFill)")
public void autoFillPointCut(){}
//通知
@Before("autoFillPointCut()")
public void autoFill(JoinPoint joinPoint){
MethodSignature signature= (MethodSignature) joinPoint.getSignature();//获取调用函数签名
AutoFill autoFill=signature.getMethod().getAnnotation(AutoFill.class);//获取到注解对象
OperationType operationType = autoFill.value();//获取注解上的value-->如何操作数据库。Insert or Update
//获取当前被拦截的方法的参数
Object[] args = joinPoint.getArgs();
if(args == null || args.length==0){
return;
}
Object entity = args[0];//要操作的对象的实体
//准备赋值的数据
LocalDateTime now = LocalDateTime.now();
Long currentId = BaseContext.getCurrentId();
//根据不同的操作类型,为对应的属性通过反射赋值
if(operationType == OperationType.INSERT) {
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, now);
setCreateUser.invoke(entity, currentId);
setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
e.printStackTrace();
}
}else{
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, now);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
SpringMvc
依赖:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
配置:
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired
private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
@Autowired
private JwtTokenUserInterceptor jwtTokenUserInterceptor;
/**
* 注册自定义拦截器
*
* @param registry
*/
protected void addInterceptors(InterceptorRegistry registry) {
log.info("开始注册自定义拦截器...");
registry.addInterceptor(jwtTokenAdminInterceptor)
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin/employee/login");
registry.addInterceptor(jwtTokenUserInterceptor)
.addPathPatterns("/user/**")
.addPathPatterns("/user/user/login")
.addPathPatterns("/user/shop/status");
}
/**
* 通过knife4j生成接口文档
* @return
*/
@Bean
public Docket docket1() {
ApiInfo apiInfo = new ApiInfoBuilder()
.title("苍穹外卖项目接口文档")
.version("2.0")
.description("苍穹外卖项目接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName("管理端")
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.sky.controller.admin"))
.paths(PathSelectors.any())
.build();
return docket;
}
@Bean
public Docket docket2() {
ApiInfo apiInfo = new ApiInfoBuilder()
.title("苍穹外卖项目接口文档")
.version("2.0")
.description("苍穹外卖项目接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName("用户端")
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.sky.controller.user"))
.paths(PathSelectors.any())
.build();
return docket;
}
/**
* 设置静态资源映射
* @param registry
*/
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* 扩展Spring Mvc的消息转换器,对数据进行转换处理
* @param converters
*/
//@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//创建一个消息转换器对象
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,java对象转换为JSON数据
converter.setObjectMapper(new JacksonObjectMapper());
//将自己的消息转换器加入到容器中
converters.add(0,converter);
}
}
@RequestParam
:用于接收url地址传参或表单传参,非json格式
@RequestBody
:用于接收json数据
@PathVariable
:用于接收路径参数,使用{参数名称}描述路径参数
@PostMapping("/status/{status}")
@ApiOperation("启用禁用分类")
public Result<String> startOrStop(@PathVariable("status") Integer status, Long id){
categoryService.startOrStop(status,id);
return Result.success();
}
异常处理器
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 捕获业务异常
* @param ex
* @return
*/
@ExceptionHandler
public Result exceptionHandler(BaseException ex){
log.error("异常信息:{}", ex.getMessage());
return Result.error(ex.getMessage());
}
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
//先获取错误信息
String message=ex.getMessage();
if(message.contains("Duplicate entry")){
String[] split=message.split(" ");
String username=split[2];
String msg=username+ MessageConstant.ALREADY_EXISTS;
return Result.error(msg);
}else{
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
}
}
SpringBoot整合Mybatis
设置数据源参数
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
LocalDate转LocalDateTime
处理精度不同,LocalDate转换为LocalDateTime
LocalDate localDate=LocalDate.now();
System.out.println("现在的时间为:");
System.out.println(localDate);
System.out.println("转换后为:");
LocalDateTime localDateTime=LocalDateTime.of(localDate, LocalTime.now());
LocalDateTime localDateTime1=LocalDateTime.of(localDate, LocalTime.MIN);
LocalDateTime localDateTime2=LocalDateTime.of(localDate, LocalTime.MAX);
System.out.println(localDateTime);
Spring Task
@Component
@Slf4j
public class OrderTask {
@Autowired
private OrderMapper orderMapper;
@Test
@Scheduled(cron = "0 * * * * ? ")
public void processTimeoutOrder(){
//每分钟触发一次
log.info("定时处理超时订单:{}", LocalDateTime.now());
//查询待付款状态的,并且已经超过15分钟了,就要取消掉
LocalDateTime time= LocalDateTime.now().plusMinutes(-15);
List<Orders> ordersList = orderMapper.findByStatusAndOrderTime(Orders.PENDING_PAYMENT, time);
if(ordersList!=null&&ordersList.size()>0){
for(Orders orders:ordersList){
orders.setStatus(Orders.CANCELLED);
orders.setCancelReason("订单超时,自动取消");
orders.setCancelTime(LocalDateTime.now());
orderMapper.update(orders);
}
}
}
}