# boot-demo **Repository Path**: liang-tian-yu/boot-demo ## Basic Information - **Project Name**: boot-demo - **Description**: 记录SpringBoot的demo用例 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-01-04 - **Last Updated**: 2025-09-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## boot-demo

Spring Boot案例

记录SpringBoot的demo用例 [TOC] ## JPA - 导入依赖 ``` org.springframework.boot spring-boot-starter-data-jpa ``` - yml配置 ``` spring: jpa: hibernate: ddl-auto: update naming: # 驼峰命名 physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl show-sql: true # 默认引擎为InnoDB database-platform: org.hibernate.dialect.MySQL5InnoDBDialect ``` - **实体类** @Entity // 作为 hibernate实体类 @Table(name = "tb_name") // 配置数据库表的名称,实体类中属性和表中字段的映射关系 - 具体测试看JpaTest ## Knife4j 接口文档 配置详见`Knife4jConfig` application.yml ``` # 解决swagger和springBoot高版本冲突问题 spring: mvc: pathmatch: matching-strategy: ANT_PATH_MATCHER ``` ## MybaisPlus 自定义生成主键策略 - 定义主键策略 ``` public class CustomIdGenerator implements IdentifierGenerator { @Override public Long nextId(Object entity) { String serialId = SerialUtil.generateSerial(); return Long.valueOf(serialId); } } ``` - 注入 ``` @Configuration @MapperScan({"com.lty.mapper","com.lty.*.mapper"}) public class MybatisPlusConfig { //@Bean //public IdentifierGenerator identifierGenerator() { // return new CustomIdGenerator(); //} } ``` - 注解使用 ``` @TableId(type = IdType.ASSIGN_ID, value = "id") private String id; ``` [油猴脚本](https://juejin.cn/post/7517081861975277603) - websocket - spring-security - boot-test - antdesign tree树使用 ## TreeUtil ```plain package com.lty.util; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; /** * @Description: 树操作方法工具类 * @author lty */ public class TreeUtil { /** * 使用Map合成树 * * @param menuList 需要合成树的List * @param pId 对象中的父ID字段,如:Menu:getPid * @param id 对象中的id字段 ,如:Menu:getId * @param rootCheck 判断E中为根节点的条件,如:x->x.getPId()==-1L , x->x.getParentId()==null,x->x.getParentMenuId()==0 * @param setSubChildren E中设置下级数据方法,如: Menu::setSubMenus * @param ID字段类型 * @param 泛型实体对象 * @return */ public static List makeTree(List menuList, Function pId, Function id, Predicate rootCheck, BiConsumer> setSubChildren) { // 按原数组顺序构建父级数据Map,使用Optional考虑pId为null Map, List> parentMenuMap = menuList.stream().collect(Collectors.groupingBy( node -> Optional.ofNullable(pId.apply(node)), LinkedHashMap::new, Collectors.toList() )); List result = new ArrayList<>(); for (E node : menuList) { // 添加到下级数据中 setSubChildren.accept(node, parentMenuMap.get(Optional.ofNullable(id.apply(node)))); // 如里是根节点,加入结构 if (rootCheck.test(node)) { result.add(node); } } return result; } /** * 树中过滤 * * @param tree 需要过滤的树 * @param predicate 过滤条件 * @param getChildren 获取下级数据方法,如:MenuVo::getSubMenus * @param 泛型实体对象 * @return List 过滤后的树 */ public static List filter(List tree, Predicate predicate, Function> getChildren) { return tree.stream().filter(item -> { if (predicate.test(item)) { List children = getChildren.apply(item); if (children != null && !children.isEmpty()) { filter(children, predicate, getChildren); } return true; } return false; }).collect(Collectors.toList()); } /** * 树中搜索 * * @param tree * @param predicate * @param getSubChildren * @param * @return 返回搜索到的节点及其父级到根节点 */ public static List search(List tree, Predicate predicate, Function> getSubChildren) { Iterator iterator = tree.iterator(); while (iterator.hasNext()) { E item = iterator.next(); List childList = getSubChildren.apply(item); if (childList != null && !childList.isEmpty()) { search(childList, predicate, getSubChildren); } if (!predicate.test(item) && (childList == null || childList.isEmpty())) { iterator.remove(); } } return tree; } } ``` ## websocket ### 后端 - 导入依赖 ```plain org.springframework.boot spring-boot-starter-websocket ``` - 配置 ```plain package com.lty.websocket; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new MyWebSocketHandler(), "/ws") .setAllowedOrigins("*"); } } ``` - 处理器 ```plain package com.lty.websocket; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class MyWebSocketHandler extends TextWebSocketHandler { private static final Set sessions = Collections.synchronizedSet(new HashSet<>()); @Override public void afterConnectionEstablished(WebSocketSession session) { sessions.add(session); log("新连接: " + session.getId()); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) { String payload = message.getPayload(); log("收到消息: " + payload); // 广播消息 sessions.forEach(s -> { if (s.isOpen() && !s.equals(session)) { try { s.sendMessage(new TextMessage("广播: " + payload)); } catch (Exception e) { log("发送消息失败: " + e.getMessage()); } } }); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { sessions.remove(session); log("连接关闭: " + session.getId()); } private void log(String message) { System.out.println("[MyWebSocketHandler] " + message); } } ``` 注意websocket地址是ws://localhost:8088/api/ws (后端地址+上下文路径+后缀) ### 前端 ```plain
```