package com.yjs.travel.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

package com.yjs.travel.config;

import com.yjs.travel.filter.JwtRequestFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    // 统一使用List.of
    private static final List<String> ALLOWED_ORIGINS = List.of(
            "http://localhost:5173", "http://127.0.0.1:5173", "https://your-production-domain.com"
    );
    private static final List<String> ALLOWED_METHODS = List.of("GET", "POST", "PUT", "DELETE", "OPTIONS");
    private static final List<String> ALLOWED_HEADERS = List.of("Authorization", "Cache-Control", "Content-Type");

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtRequestFilter jwtRequestFilter) throws Exception {
        return http
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(
                                "/api/auth/**",
                                "/api/area/**",
                                "/public/**",
                                "/error",
                                "/v3/api-docs/**",
                                "/swagger-ui/**"
                        ).permitAll()
                        .anyRequest().authenticated()
                )
                .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(ALLOWED_ORIGINS);
        config.setAllowedMethods(ALLOWED_METHODS);
        config.setAllowedHeaders(ALLOWED_HEADERS);
        config.setAllowCredentials(true);
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

// AreaController.java
package com.yjs.travel.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yjs.travel.entity.Area;
import com.yjs.travel.service.AreaService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.function.Supplier;

@RestController
@RequestMapping("/api/area")
@RequiredArgsConstructor
public class AreaController {
    private final AreaService areaService;

    // 统一异常处理函数
    private <T> ResponseEntity<T> handleRequest(Supplier<ResponseEntity<T>> supplier) {
        try {
            return supplier.get();
        } catch (RuntimeException e) {
            return ResponseEntity.badRequest().build();
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    // 修改：添加分页参数，返回分页对象
    @GetMapping
    public ResponseEntity<IPage<Area>> getAllAreas(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize) {
        return handleRequest(() -> ResponseEntity.ok(areaService.getAllAreas(pageNum, pageSize)));
    }

    @GetMapping("/{id}")
    public ResponseEntity<Area> getAreaById(@PathVariable Integer id) {
        return handleRequest(() -> {
            Area area = areaService.getAreaById(id);
            return area != null ? ResponseEntity.ok(area) : ResponseEntity.notFound().build();
        });
    }

    @PostMapping
    public ResponseEntity<Area> addArea(@RequestBody Area area) {
        area.setAreaId(null);
        return handleRequest(() -> ResponseEntity.ok(areaService.saveArea(area)));
    }

    @PutMapping("/{id}")
    public ResponseEntity<Area> updateArea(@PathVariable Integer id, @RequestBody Area area) {
        area.setAreaId(id);
        return handleRequest(() -> {
            Area updatedArea = areaService.updateArea(area);
            return updatedArea != null ?
                    ResponseEntity.ok(updatedArea) :
                    ResponseEntity.notFound().build();
        });
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteArea(@PathVariable Integer id) {
        return handleRequest(() -> {
            areaService.deleteArea(id);
            return ResponseEntity.noContent().build();
        });
    }
}

package com.yjs.travel.controller;

import com.yjs.travel.entity.User;
import com.yjs.travel.service.UserService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
    private final UserService userService;

    private static final String REGISTER_SUCCESS = "注册成功";
    private static final String PASSWORD_MISMATCH = "两次密码不一致";

    @PostMapping("/register")
    public ResponseEntity<?> register(@RequestBody RegisterRequest request) {
        if (!request.getPassword().equals(request.getConfirmPassword())) {
            return ResponseEntity.badRequest().body(PASSWORD_MISMATCH);
        }

        try {
            userService.registerUser(request.userName, request.password, request.role);
            return ResponseEntity.ok(REGISTER_SUCCESS);
        } catch (RuntimeException e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest request) {
        try {
            return ResponseEntity.ok(userService.authenticate(
                    request.userName, request.password, request.role));
        } catch (RuntimeException e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }

    @Data
    public static class RegisterRequest {
        private String userName;
        private String password;
        private String confirmPassword;
        private String role = "user";
    }

    @Data
    public static class LoginRequest {
        private String userName;
        private String password;
        private String role;
    }
}

// src/main/java/com/yjs/travel/entity/Area.java
package com.yjs.travel.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@TableName("area")
public class Area {
    @TableId(type = IdType.AUTO)
    private Integer areaId;

    private String continent;
    private String country;
    private String province;
    private String city;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

// src/main/java/com/yjs/travel/entity/User.java
package com.yjs.travel.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Data
@TableName("users")
public class User {
    @TableId(type = IdType.AUTO)
    private Long userId;

    @TableField("user_name")
    private String userName;

    private String nickName;
    private String email;
    private String phoneNumber;
    private String gender = "0";
    private LocalDate birthday;
    private String password;
    private String role = "user";

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

package com.yjs.travel.filter;

import com.yjs.travel.service.UserService;
import com.yjs.travel.utils.JwtUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
@RequiredArgsConstructor
public class JwtRequestFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;
    private final UserService userService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            String jwt = header.substring(7);
            String username = jwtUtil.extractUsername(jwt);

            if (username != null && noExistingAuthentication() && jwtValidForUser(jwt, username)) {
                setSecurityAuthentication(username, request);
            }
        }
        chain.doFilter(request, response);
    }

    private boolean noExistingAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication() == null;
    }

    private boolean jwtValidForUser(String jwt, String username) {
        return jwtUtil.validateToken(jwt) && userService.validateToken(username, jwt);
    }

    private void setSecurityAuthentication(String username, HttpServletRequest request) {
        UserDetails userDetails = userService.loadUserByUsername(username);

        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities());

        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}

// src/main/java/com/yjs/travel/handler/MyMetaObjectHandler.java
package com.yjs.travel.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

// src/main/java/com/yjs/travel/mapper/AreaMapper.java
package com.yjs.travel.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yjs.travel.entity.Area;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.Optional;

@Mapper
public interface AreaMapper extends BaseMapper<Area> {

    @Select("SELECT * FROM area " +
            "WHERE continent = #{continent} " +
            "AND country = #{country} " +
            "AND province = #{province} " +
            "AND city = #{city}")
    Optional<Area> findByContinentAndCountryAndProvinceAndCity(
            @Param("continent") String continent,
            @Param("country") String country,
            @Param("province") String province,
            @Param("city") String city);
}

// src/main/java/com/yjs/travel/mapper/UserMapper.java
package com.yjs.travel.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yjs.travel.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.Optional;

@Mapper
public interface UserMapper extends BaseMapper<User> {

    // 添加注解实现方法
    @Select("SELECT * FROM users WHERE user_name = #{userName}")
    Optional<User> findByUserName(String userName);
}

// AreaService.java
package com.yjs.travel.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yjs.travel.entity.Area;
import com.yjs.travel.mapper.AreaMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
@RequiredArgsConstructor
public class AreaService {
    private final AreaMapper areaMapper;

    // 修改：增加分页查询方法
    public Page<Area> getAllAreas(int pageNum, int pageSize) {
        Page<Area> page = new Page<>(pageNum, pageSize);
        return areaMapper.selectPage(page, null);
    }

    public Area saveArea(Area area) {
        validateAreaUniqueness(area);
        if (area.getAreaId() == null) {
            areaMapper.insert(area);
        } else {
            areaMapper.updateById(area);
        }
        return area;
    }

    public Area getAreaById(Integer areaId) {
        return Optional.ofNullable(areaMapper.selectById(areaId))
                .orElseThrow(() -> new RuntimeException("地区不存在"));
    }

    public Area updateArea(Area area) {
        if (areaMapper.selectById(area.getAreaId()) == null) {
            throw new RuntimeException("地区不存在，无法更新");
        }
        return saveArea(area);
    }

    public void deleteArea(Integer areaId) {
        areaMapper.deleteById(areaId);
    }

    private void validateAreaUniqueness(Area area) {
        Optional<Area> existing = areaMapper.findByContinentAndCountryAndProvinceAndCity(
                area.getContinent(), area.getCountry(), area.getProvince(), area.getCity()
        );
        if (existing.isPresent() && !sameArea(area, existing.get())) {
            throw new RuntimeException("该地区信息已存在");
        }
    }

    private boolean sameArea(Area area1, Area area2) {
        return area1.getAreaId() != null && area1.getAreaId().equals(area2.getAreaId());
    }
}

// src/main/java/com/yjs/travel/service/UserService.java
package com.yjs.travel.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yjs.travel.entity.User;
import com.yjs.travel.mapper.UserMapper;
import com.yjs.travel.utils.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;
    private final RedisTemplate<String, String> redisTemplate;

    public User registerUser(String userName, String password, String role) {
        if (userMapper.exists(new QueryWrapper<User>().eq("user_name", userName))) {
            throw new RuntimeException("用户名已存在");
        }

        User user = new User();
        user.setUserName(userName);
        user.setNickName(userName);
        user.setPassword(passwordEncoder.encode(password));
        user.setRole(role);

        userMapper.insert(user);
        return user;
    }

    public String authenticate(String userName, String password, String role) {
        User user = getUserByUserName(userName);

        if (!isPasswordValid(password, user) || !isRoleValid(role, user)) {
            throw new RuntimeException("登录失败,密码或身份错误");
        }

        String token = jwtUtil.generateToken(userName);
        storeTokenInRedis(userName, token);
        return token;
    }

    public boolean validateToken(String userName, String token) {
        String storedToken = redisTemplate.opsForValue().get(userName);
        return token.equals(storedToken);
    }

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = getUserByUserName(username);

        return new org.springframework.security.core.userdetails.User(
                user.getUserName(),
                user.getPassword(),
                Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + user.getRole().toUpperCase()))
        );
    }

    private User getUserByUserName(String userName) {
        return userMapper.findByUserName(userName)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + userName));
    }

    private boolean isPasswordValid(String password, User user) {
        return passwordEncoder.matches(password, user.getPassword());
    }

    private boolean isRoleValid(String role, User user) {
        return role.equals(user.getRole());
    }

    private void storeTokenInRedis(String userName, String token) {
        redisTemplate.opsForValue().set(userName, token, 2, TimeUnit.HOURS);
    }
}

package com.yjs.travel.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private long expiration;

    // 生成密钥
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }

    // 生成JWT令牌
    public String generateToken(String userName) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, userName);
    }

    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(getSigningKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    // 从令牌中提取用户名
    public String extractUsername(String token) {
        return getClaims(token).getSubject();
    }

    // 验证令牌有效性
    public boolean validateToken(String token) {
        try {
            return !isTokenExpired(token);
        } catch (Exception e) {
            return false;
        }
    }

    // 检查令牌是否过期
    private boolean isTokenExpired(String token) {
        return getClaims(token).getExpiration().before(new Date());
    }

    // 获取声明
    private Claims getClaims(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}

// src/main/java/com/yjs/travel/TrackTravelApplication.java
package com.yjs.travel;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.yjs.travel.mapper")
public class TrackTravelApplication {
    public static void main(String[] args) {
        SpringApplication.run(TrackTravelApplication.class, args);
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yjs.travel.mapper.AreaMapper">
    <select id="selectAll" resultType="com.yjs.travel.entity.Area">
        SELECT * FROM area
    </select>

    <select id="selectByLocation" resultType="com.yjs.travel.entity.Area">
        SELECT * FROM area
        WHERE continent = #{continent}
          AND country = #{country}
          AND province = #{province}
          AND city = #{city}
            LIMIT 1
    </select>
</mapper>

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/track?useSSL=false&serverTimezone=UTC&characterEncoding=utf8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

  jackson:
    time-zone: Asia/Shanghai
    date-format: yyyy-MM-dd HH:mm:ss

  data:
    redis:
      host: localhost
      port: 6379

# JWT配置
jwt:
  secret: your-strong-secret-key-with-at-least-256-bits  # 替换为安全的密钥
  expiration: 7200000  # 2小时（单位毫秒）

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.yjs</groupId>
    <artifactId>travel</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Track-Travel</name>
    <description>Track-Travel</description>
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>3.5.0</spring-boot.version>
    </properties>
    <dependencies>
        <!--web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--mysql依赖-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- MyBatis Plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.12</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-jsqlparser</artifactId>
            <version>3.5.12</version>
        </dependency>

        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- BCrypt -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-crypto</artifactId>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- JWT -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>

        <!-- Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>5.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.yjs.travel.TrackTravelApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
根据上面代码，我想把项目的安全配置Spring Security转化成Sa-Token，给我完整代码