# springboot-api **Repository Path**: miaokela/springboot-api ## Basic Information - **Project Name**: springboot-api - **Description**: restapi需要的相关组件 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-02-28 - **Last Updated**: 2024-03-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringBoot, Java ## README ## Spring Boot简易代码 ### 整合mybatisplus ##### 引入依赖 ```xml mysql mysql-connector-java 8.0.25 com.baomidou mybatis-plus-boot-starter ${mybatis.version} ``` ##### 配置文件 application.yml ```yaml spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:6666/springboot_demo hikari: minimum-idle: 5 maximum-pool-size: 20 auto-commit: true idle-timeout: 30000 pool-name: MyHikariCP max-lifetime: 1800000 connection-timeout: 30000 mybatis-plus: mapper-locations: classpath*:mappers/*.xml ``` ##### 实体类 ```java @Data @TableName("`user`") // 表注解 public class User { @TableId(type = IdType.AUTO) // 主键注解 private Long id; private String name; private Integer age; private String email; } ``` ##### mapper接口 ```java // mapper.UserMapper public interface UserMapper extends BaseMapper { } ``` ##### 直接使用Mapper处理数据 ```java @SpringBootTest(classes = Application.class) public class SampleTest { @Autowired private UserMapper userMapper; @Test public void testSelect() { System.out.println("测试..."); List list = userMapper.selectList(null); System.out.println(list); list.forEach(item -> { System.out.println("Name:" + item.getName()); }); } @Test public void testInsert() { User user = new User(); user.setName("John Doe"); user.setAge(30); user.setEmail("john.doe@example.com"); userMapper.insert(user); } @Test public void testUpdate() { User userToUpdate = userMapper.selectById(1L); userToUpdate.setEmail("new.email@example.com"); userMapper.updateById(userToUpdate); } @Test public void testSelectById() { User user = userMapper.selectById(1L); System.out.println(user); } @Test public void deleteById() { userMapper.deleteById(1L); } } ``` ##### 使用IService接口的方式 * 继承IService接口 ```java public interface UserService extends IService { } ``` * 继承ServiceImpl接口,实现UserService的实现类 ```java @Service public class UserServiceImpl extends ServiceImpl implements UserService { } ``` * 测试IService方式 ```java @Test public void testInsertService() { User user = new User(); user.setName("John Doe"); user.setAge(30); user.setEmail("john.doe@example.com"); userService.save(user); } @Test public void testDeleteService() { userService.removeById(1L); } @Test public void testUpdateService() { User userToUpdate = userService.getById(2L); userToUpdate.setEmail("new.email@example.com"); userService.updateById(userToUpdate); } @Test public void testSelectService() { List list = userService.list(); System.out.println(list); list.forEach(item -> { System.out.println("Name:" + item.getName()); }); } @Test public void testSelectByIdService() { User user = userService.getById(2L); System.out.println(user); } ``` ##### 复杂的数据处理 ```java @SpringBootTest(classes = Application.class) public class SampleTest { @Autowired private UserMapper userMapper; /** * QueryWrapper */ @Test public void testQueryWrapper() { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name", "John Doe") .between("age", 20, 30) .isNotNull("email"); List users = userMapper.selectList(queryWrapper); System.out.println(users); } /** * UpdateWrapper */ @Test public void testUpdateWrapper() { UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.set("email", "new.email@example.com") .eq("name", "John Doe") .between("age", 20, 30) .isNotNull("email"); int rows = userMapper.update(null, updateWrapper); System.out.println(rows + " rows updated"); } /** * Wrapper自定义SQL */ @Test public void testWrapper() { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.apply("name = {0}", "John Doe"); List users = userMapper.selectList(queryWrapper); System.out.println(users); } /** * LambdaQueryWrapper */ @Test public void testLambdaQueryWrapper() { LambdaQueryWrapper userLambdaQueryWrapper = Wrappers.lambdaQuery(User.class); userLambdaQueryWrapper.eq(User::getName, "John Doe") .between(User::getAge, 20, 30) .isNotNull(User::getEmail); List users = userMapper.selectList(userLambdaQueryWrapper); System.out.println(users); } /** * LambdaUpdateWrapper */ @Test public void testLambdaUpdateWrapper() { LambdaUpdateWrapper userLambdaUpdateWrapper = Wrappers.lambdaUpdate(User.class); userLambdaUpdateWrapper.set(User::getEmail, "new.email@example.com") .eq(User::getName, "John Doe") .between(User::getAge, 20, 30) .isNotNull(User::getEmail); int rows = userMapper.update(null, userLambdaUpdateWrapper); System.out.println(rows + " rows updated"); } /** * 复杂的查询 比如连表 */ @Test public void testSelectWithOrder() { OrderUserDTO orderUserDTO = orderWithUserMapper.selectOrderWithUser(1L); System.out.println(orderUserDTO); } } ``` ##### 复杂数据查询 * 定义Mapper接口 ```java public interface OrderWithUserMapper { OrderUserDTO selectOrderWithUser(Long orderId); } ``` * 编写mapper映射的xml ```xml ``` * 编写实体类 ```java @Data public class OrderUserDTO { private Long orderId; private String orderDetails; private Long userId; private String userName; } ``` * 测试查询 ```java @SpringBootTest(classes = Application.class) public class SampleTest { @Autowired private OrderWithUserMapper orderWithUserMapper; /** * 复杂的查询 比如连表 */ @Test public void testSelectWithOrder() { OrderUserDTO orderUserDTO = orderWithUserMapper.selectOrderWithUser(1L); System.out.println(orderUserDTO); } } ``` ### 统一响应格式 ```java // utils.ApiResponse @Data public class ApiResponse { private int code; private String message; private T data; public ApiResponse(int code, String message, T data) { this.code = code; this.message = message; this.data = data; } } ``` ### 全局异常处理 ```java // utils.GlobalExceptionHandler @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ApiResponse hanldeException(Exception e) { return new ApiResponse<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器内部错误", null); } } ``` ### Swagger接口文档 ##### 引入依赖 ```xml com.github.xiaoymin knife4j-spring-boot-starter 3.0.2 ``` ##### 编写配置类 ```java @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.quickstart.controller")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("API 文档") .description("API 文档描述") .version("1.0") .build(); } } ``` ##### 访问地址 > http://localhost:8080/doc.html ### 基础jwt认证 ##### 引入依赖 ```xml org.springframework.boot spring-boot-starter-security io.jsonwebtoken jjwt 0.9.1 ``` ##### JWT处理工具类 > 生成token,校验token ```java @Component public class JwtUtil { private String secret = "yourSecretKey"; // 用于签名和验证JWT的密钥 private Integer expireTime = 1000 * 60 * 60 * 10; // 从JWT令牌中提取用户名 public String getUsernameFromToken(String token) { return getClaimFromToken(token, Claims::getSubject); } // 从JWT令牌中提取特定的声明(claim) public T getClaimFromToken(String token, Function claimsResolver) { try { final Claims claims = getAllClaimsFromToken(token); return claimsResolver.apply(claims); } catch (Exception e) { return null; } } // 为获取任何信息而解析JWT令牌 private Claims getAllClaimsFromToken(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } // 验证JWT令牌 public Boolean validateToken(String token, UserDetails userDetails) { final String username = getUsernameFromToken(token); return (username.equals(userDetails.getUsername())); } // 生成JWT令牌 public String generateToken(UserDetails userDetails) { return Jwts.builder() .setSubject(userDetails.getUsername()) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + expireTime)) // 设置过期时间 .signWith(SignatureAlgorithm.HS512, secret).compact(); } } ``` ##### 添加过滤器 ```java @Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; @Autowired private JwtUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String authToken = request.getHeader("Authorization"); if (authToken != null && authToken.startsWith("Bearer ")) { authToken = authToken.substring(7); String username = jwtUtil.getUsernameFromToken(authToken); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(authToken, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); } } } chain.doFilter(request, response); } } ``` ##### 注册过滤器 ```java @Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; @Autowired private JwtUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String authToken = request.getHeader("Authorization"); if (authToken != null && authToken.startsWith("Bearer ")) { authToken = authToken.substring(7); String username = jwtUtil.getUsernameFromToken(authToken); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(authToken, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); } } } chain.doFilter(request, response); } } ``` 获取用户信息 > 上面提到一个Spring Security的UserDetailsService的实现,用来获取用户信息 ```java @Service public class CustomUserDetailsService implements UserDetailsService { private final PasswordEncoder passwordEncoder; public CustomUserDetailsService(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // TODO 这里仅为示例,实际应用中应该从数据库或其他地方根据用户名查找用户信息 if ("admin".equals(username)) { return User.builder() .username("admin") .password(passwordEncoder.encode("password")) .roles("ADMIN") // 或者.authorities("ROLE_ADMIN") .build(); } else { throw new UsernameNotFoundException("User not found with username: " + username); } } } ``` ### 整合redis ##### 引入依赖 ```xml org.springframework.boot spring-boot-starter-data-redis io.lettuce lettuce-core redis.clients jedis ``` ##### 添加配置 ```xml spring: redis: host: localhost port: 6379 timeout: 1000 jedis: min-idle: 5 max-idle: 10 max-active: 10 max-wait: 2000 ``` ##### 创建配置类 ```java @Configuration public class RedisConfig { @Bean public RedisTemplate redisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 设置序列化工具,这里使用JSON序列化 Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class); // 配置RedisTemplate template.setValueSerializer(jacksonSeial); template.setHashValueSerializer(jacksonSeial); template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } } ``` 测试插入 ```java @SpringBootTest(classes = Application.class) public class QuickStartTest { @Autowired private RedisTemplate redisTemplate; @Test public void testInsertRedis() { redisTemplate.opsForValue().set("name", "miaokela"); } } ``` ### 定时任务 Task ##### 配置类 ```java @Component public class MyScheduledTasks { @Scheduled(fixedRate = 5000) public void resportCurrentTime() { System.out.println("当前时间: " + System.currentTimeMillis()); } @Scheduled(cron = "0 0 1 * * ?") public void executeDaily() { System.out.println("执行日常任务"); } } ``` ##### 注册 ```java @SpringBootApplication @MapperScan("com.quickstart.mapper") @EnableScheduling public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` ### Docker部署 ##### Dockerfile ```Dockerfile # 使用官方Java运行时环境作为基础镜像 FROM openjdk:8-jdk-alpine # 指定维护者信息 LABEL maintainer="yourname@example.com" # 添加一个卷,指向外部的/tmp,因为Spring Boot使用的内嵌Tomcat容器默认使用/tmp作为工作目录 VOLUME /tmp # 将jar文件添加到容器中 ADD target/myproject-1.0-SNAPSHOT.jar myproject-1.0-SNAPSHOT.jar # 声明运行时容器提供服务端口 EXPOSE 8080 # 配置容器启动后执行的命令 ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/myproject-1.0-SNAPSHOT.jar"] ``` ##### 创建镜像 ``` docker build -t spring-boot-app . ``` 创建并运行容器 ```shell docker run -d -p 8081:8080 spring-boot-app ```