苍穹外卖学习知识点
整体概括:
学到目前(day10),总体最核心的部分就是CURD各种数据,因为一些接口,前端页面都已经设计好,在实际开发中也应该是这样,重点是在每个不同的业务板块区别出细微不同的业务逻辑
Swagger注解
swagger是一种自动生成接口文档的插件
使用注解,就可以在在接口文档处测试代码的功能
swagger2中常见的注解
@Api()
在controller上的注解,收集了某一个controller类中的所有方法,tags属性给集合起名字
@ApiOperation()
在controller中方法上的注解 value属性起名字
swagger3中常见注解
@Tag()
就相当于@Api
@Operation()
相当于@ApiOperation
新知识:给接口分组
项目中controller层分为用户端和管理端两个大类,会出现同名的类,所以在测试是我们分为两组较为合适
swagger2中实现接口分组需要docket配置
@Beanpublic 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;}
修改`.groupname()`和`.basePackage()`即可
在学习mybatis plus的时候,学习过knife4j,是swagger的增强类,它提供了 更友好的 API 文档界面,并增强了 接口调试 和 API 分组 功能。
knife4j实现了自动分组,只需要在@Tag()注解中的name属性中加入分组,此时接口文档就可以实现分组
此外也可以在配置类中实现分组
@Configuration
public class SwaggerConfig {
@Beanpublic GroupedOpenApi userApi() {return GroupedOpenApi.builder().group("用户端 API") // 自动分组名称.packagesToScan("com.example.controller.user") // 只扫描 user 相关的 Controller.build();}
@Beanpublic GroupedOpenApi adminApi() {return GroupedOpenApi.builder().group("管理端 API") // 自动分组名称.packagesToScan("com.example.controller.admin") // 只扫描 admin 相关的 Controller.build();}
}
还可以在yml文件中实现分组(原生swagger3就支持)
springdoc:group-configs:- group: 用户端 APIpaths-to-match: /user/**- group: 管理端 APIpaths-to-match: /admin/**
小型项目推荐使用@Tag()注解
员工相关代码开发
新增员工
比较简单
员工分页查询
接收分页查询的DTO封装了name(可以通过姓名模糊查询) pagesize pagenum
启用禁用员工账号 编辑员工
就是简单的修改员工
mapper层要编写动态sql
菜品相关代码开发
在这块业务要注意的是菜品有两个表,菜品表和菜品口味表,两个表都要做增删改查
公共字段填充
比如在添加菜品和修改菜品时,修改时间和修改人,创建时间和创建人这类代码都是固定的
可以在属性赋值的时候用set方法,还有就是自定义注解,创建一个方法实现代码
自定义注解使用到了AOP编程
1.编写切入点表达式@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill) ")public void autoFillPointCut() {}
2.使用前置通知实现公共字段填充@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint){// 获取当前被拦截的方法MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取方法签名(方法名 )AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);//获取方法上的注解对象OperationType operationType = annotation.value();//获得数据库操作类型Object[] args = joinPoint.getArgs();//获取方法参数if (args.length == 0 || args[0] == null){return;}Object arg = args[0];//获取对象//准备赋值的数据Long currentId = BaseContext.getCurrentId();LocalDateTime now = LocalDateTime.now();
if (operationType == OperationType.INSERT){//设置创建时间和创建人try {Method setCreateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCreateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);setCreateTime.invoke(arg,now);setCreateUser.invoke(arg,currentId);setUpdateTime.invoke(arg,now);setUpdateUser.invoke(arg,currentId);
} catch (Exception e) {e.printStackTrace();}} else if (operationType == OperationType.UPDATE) {//设置更新时间和更新人try {Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);setUpdateTime.invoke(arg,now);setUpdateUser.invoke(arg,currentId);} catch (Exception e) {e.printStackTrace();}}}
新增菜品和修改菜品并没有什么特殊的业务逻辑,正常的增改
删除菜品(批量删除)
传入多个id值
Redis基础及应用
redis也是一个数据存储系统,但他把数据存在内存中,这样的优点是方便一些经常需要读取或修改的数据快速读取
redis可以存储的数据类型
-
字符串
-
列表list 有序可重复
-
哈希Hash
-
集合Set
-
有序集合ZSet
具体的操作以后在学
在java中使用redis
1.导入maven坐标
2.配置redis数据源
3.编写redis配置类,创建RedisTemplate对象
4.注入redisTemplate并使用
SpringCache
Spring Cache 是 Spring Framework 提供的一个缓存抽象机制,它使得你可以很容易地集成各种缓存技术,比如 Redis、Ehcache、Guava Cache 等。Spring Cache 提供了基于注解的简单缓存操作,如 @Cacheable
、@CachePut
、@CacheEvict
等。
@EnableCache开启缓存
@Cacheable
: 把方法的返回结果存到内存中,但如果缓存中有对应的值,就不会执行此方法
@Cacheput
: 无论缓存中有没有对应的值,方法都会执行并且更新数据
@CacheEvict
: 删除指定值
缓存套餐
加上注解就好
购物车代码开发
新增购物车
要注意的是此操作为一条一条增加,不能批量操作
删除购物车
根据userId删除购物车就行,一般是清空
Spring Task运用
springtask就是给方法添加注解使其定时执行
在启动类上添加@Scheduled
注解
在注解@Schedule
中添加cron表达式即可
在项目中的运用是定时清理一些订单(已完成但未勾选已送达)修改订单状态
WebSocket
是一种实现长连接的技术,客户端和服务端实现一次交互就开启长连接,它在 单个 TCP 连接 上进行双向数据传输,适用于需要实时数据交换的应用场景,如聊天、在线游戏、股票行情推送等。
WebSocket 工作原理
WebSocket 连接的建立流程如下:
-
客户端发送 WebSocket 握手请求(基于 HTTP 请求,带
Upgrade: websocket
头部)。 -
服务器同意升级协议(返回
101 Switching Protocols
响应)。 -
连接建立后,双方可以自由发送数据(数据使用 WebSocket 帧格式,不是 HTTP 报文)。
-
任何一方可以主动关闭连接。
实现步骤
基于springboot
1.编写服务端import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.concurrent.CopyOnWriteArraySet;
@Component
public class MyWebSocketHandler extends TextWebSocketHandler {
private static final CopyOnWriteArraySet<WebSocketSession> sessions = new CopyOnWriteArraySet<>();
@Overridepublic void afterConnectionEstablished(WebSocketSession session) {sessions.add(session);System.out.println("新连接: " + session.getId());}
@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {System.out.println("收到消息: " + message.getPayload());// 广播消息给所有连接for (WebSocketSession s : sessions) {s.sendMessage(new TextMessage("服务器收到: " + message.getPayload()));}}
@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) {sessions.remove(session);System.out.println("连接关闭: " + session.getId());}
}
2.注册配置类import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.*;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*"); // 允许所有跨域}
}
原生javaee
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {
//存放会话对象private static Map<String, Session> sessionMap = new HashMap();
/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {System.out.println("客户端:" + sid + "建立连接");sessionMap.put(sid, session);}
/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, @PathParam("sid") String sid) {System.out.println("收到来自客户端:" + sid + "的信息:" + message);}
/*** 连接关闭调用的方法** @param sid*/@OnClosepublic void onClose(@PathParam("sid") String sid) {System.out.println("连接断开:" + sid);sessionMap.remove(sid);}
Apache ECharts
是一个前端技术,我们只需要按照要求把数据传给前端就好
Apache POI
通过代码对excel文件进行创建,读取,修改等操作
1.读取
import org.apache.poi.xssf.usermodel.*;
import java.io.FileInputStream;
public class ReadExcel {public static void main(String[] args) throws Exception {FileInputStream fis = new FileInputStream("example.xlsx");XSSFWorkbook workbook = new XSSFWorkbook(fis);XSSFSheet sheet = workbook.getSheetAt(0);
for (XSSFRow row : sheet) {for (XSSFCell cell : row) {System.out.print(cell.toString() + "\t");}System.out.println();}workbook.close();}
}
2.写入
public class WriteExcel {public static void main(String[] args) throws Exception {XSSFWorkbook workbook = new XSSFWorkbook();XSSFSheet sheet = workbook.createSheet("Sheet1");
XSSFRow row = sheet.createRow(0);XSSFCell cell = row.createCell(0);cell.setCellValue("Hello, POI!");
FileOutputStream fos = new FileOutputStream("output.xlsx");workbook.write(fos);fos.close();workbook.close();}
}
要点
要根据表格的格式来查找或新增数据