First backend commit //main focus on Auth and JWT service not available for now

Change-Id: Ifccbc53798588f91244e095d6072990ac9e0b9fa
diff --git a/backend/demo/src/main/java/com/example/demo/DemoApplication.java b/backend/demo/src/main/java/com/example/demo/DemoApplication.java
index 1f94219..8575ec8 100644
--- a/backend/demo/src/main/java/com/example/demo/DemoApplication.java
+++ b/backend/demo/src/main/java/com/example/demo/DemoApplication.java
@@ -1,8 +1,10 @@
 package com.example.demo;
 
+import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 @SpringBootApplication
+@MapperScan("com.example.demo.mapper")
 public class DemoApplication {
 
 	public static void main(String[] args) {
diff --git a/backend/demo/src/main/java/com/example/demo/config/JWTProperties.java b/backend/demo/src/main/java/com/example/demo/config/JWTProperties.java
new file mode 100644
index 0000000..e96ed56
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/config/JWTProperties.java
@@ -0,0 +1,91 @@
+package com.example.demo.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * JWT 配置属性,从 application.properties 中 jwt 开头的配置加载
+ */
+@Component
+@ConfigurationProperties(prefix = "jwt")
+public class JWTProperties {
+    /**
+     * 用于签名的密钥
+     */
+    private String secret;
+
+    /**
+     * Token 过期时长,单位毫秒
+     */
+    private long expirationMs;
+
+    /**
+     * HTTP Header 中放置 JWT 的字段名
+     */
+    private String header = "Authorization";
+
+    /**
+     * Header 中 Token 的前缀
+     */
+    private String tokenPrefix = "Bearer ";
+
+    /**
+     * 签发者信息(可选)
+     */
+    private String issuer;
+
+    /**
+     * 接收者信息(可选)
+     */
+    private String audience;
+
+    // --- getters & setters ---
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
+
+    public long getExpirationMs() {
+        return expirationMs;
+    }
+
+    public void setExpirationMs(long expirationMs) {
+        this.expirationMs = expirationMs;
+    }
+
+    public String getHeader() {
+        return header;
+    }
+
+    public void setHeader(String header) {
+        this.header = header;
+    }
+
+    public String getTokenPrefix() {
+        return tokenPrefix;
+    }
+
+    public void setTokenPrefix(String tokenPrefix) {
+        this.tokenPrefix = tokenPrefix;
+    }
+
+    public String getIssuer() {
+        return issuer;
+    }
+
+    public void setIssuer(String issuer) {
+        this.issuer = issuer;
+    }
+
+    public String getAudience() {
+        return audience;
+    }
+
+    public void setAudience(String audience) {
+        this.audience = audience;
+    }
+}
diff --git a/backend/demo/src/main/java/com/example/demo/config/SecurityConfig.java b/backend/demo/src/main/java/com/example/demo/config/SecurityConfig.java
new file mode 100644
index 0000000..bfd7b1b
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/config/SecurityConfig.java
@@ -0,0 +1,51 @@
+package com.example.demo.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+import com.example.demo.security.JwtAuthenticationFilter;
+import com.example.demo.security.JwtTokenUtil;
+
+@Configuration
+public class SecurityConfig {
+
+    /**
+     * 密码加密器,用于注册用户时对密码加密、登录时校验
+     */
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+
+    /**
+     * 将 Spring Security 的 AuthenticationManager 暴露为 Bean,
+     * 方便在 AuthController 或其它地方手动调用。
+     */
+    @Bean
+    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
+        return config.getAuthenticationManager();
+    }
+
+    /**
+     * 核心安全策略:禁用 CSRF、无状态 Session、开放登录接口、其余接口需认证。
+     */
+    @Bean
+public SecurityFilterChain filterChain(HttpSecurity http,
+                                       JwtTokenUtil tokenUtil,
+                                       JWTProperties props) throws Exception {
+    JwtAuthenticationFilter jwtFilter = new JwtAuthenticationFilter(tokenUtil, props);
+    http
+      // 省略其他配置…
+      .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
+    return http.build();
+}
+}
+
diff --git a/backend/demo/src/main/java/com/example/demo/controller/AuthController.java b/backend/demo/src/main/java/com/example/demo/controller/AuthController.java
new file mode 100644
index 0000000..08411d7
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/controller/AuthController.java
@@ -0,0 +1,74 @@
+package com.example.demo.controller;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.example.demo.dto.LoginRequestDTO;
+import com.example.demo.dto.LoginResponseDTO;
+import com.example.demo.entity.User;
+import com.example.demo.exception.AuthException;
+import com.example.demo.security.JwtTokenUtil;
+import com.example.demo.service.UserService;
+
+import jakarta.validation.Valid;
+
+@RestController
+@RequestMapping("/api/auth")
+public class AuthController {
+
+    private final UserService userService;
+    private final PasswordEncoder passwordEncoder;
+    private final JwtTokenUtil jwtTokenUtil;
+
+    @Autowired
+    public AuthController(UserService userService,
+                          PasswordEncoder passwordEncoder,
+                          JwtTokenUtil jwtTokenUtil) {
+        this.userService = userService;
+        this.passwordEncoder = passwordEncoder;
+        this.jwtTokenUtil = jwtTokenUtil;
+    }
+
+    @PostMapping("/login")
+    public ResponseEntity<?> login(
+            @Valid @RequestBody LoginRequestDTO loginRequest,
+            BindingResult bindingResult) {
+
+        if (bindingResult.hasErrors()) {
+            String errMsg = bindingResult.getFieldErrors().stream()
+                .map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
+                .reduce((a, b) -> a + "; " + b)
+                .orElse("Invalid parameters");
+            return ResponseEntity.badRequest().body(Map.of("error", errMsg));
+        }
+
+        User user = userService.lambdaQuery()
+                .eq(User::getUsername, loginRequest.getUsername())
+                .one();
+
+        if (user == null || !passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
+            throw new AuthException("用户名或密码错误");
+        }
+
+        String token = jwtTokenUtil.generateToken(user.getId(), user.getUsername(), user.getRole());
+
+        LoginResponseDTO response = new LoginResponseDTO();
+        response.setToken(token);
+        response.setExpiresAt(Instant.now().plusMillis(jwtTokenUtil.getExpiration()));
+        response.setUserId(user.getId());
+        response.setUsername(user.getUsername());
+        response.setRoles(List.of(user.getRole()));
+
+        return ResponseEntity.ok(response);
+    }
+}
diff --git a/backend/demo/src/main/java/com/example/demo/dto/LoginRequestDTO.java b/backend/demo/src/main/java/com/example/demo/dto/LoginRequestDTO.java
new file mode 100644
index 0000000..8c85fec
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/dto/LoginRequestDTO.java
@@ -0,0 +1,32 @@
+package com.example.demo.dto;
+
+import java.io.Serializable;
+
+import jakarta.validation.constraints.NotBlank;
+
+
+public class LoginRequestDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @NotBlank(message = "用户名不能为空")
+    private String username;
+
+    @NotBlank(message = "密码不能为空")
+    private String password;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}
\ No newline at end of file
diff --git a/backend/demo/src/main/java/com/example/demo/dto/LoginResponseDTO.java b/backend/demo/src/main/java/com/example/demo/dto/LoginResponseDTO.java
new file mode 100644
index 0000000..2dd6241
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/dto/LoginResponseDTO.java
@@ -0,0 +1,64 @@
+package com.example.demo.dto;
+
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.List;
+
+public class LoginResponseDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 登录成功后返回的 JWT 或会话标识 */
+    private String token;
+
+    /** Token 过期时间戳 */
+    private Instant expiresAt;
+
+    /** 用户 ID,可选 */
+    private Long userId;
+
+    /** 用户名,可选 */
+    private String username;
+
+    /** 用户角色列表,可选 */
+    private List<String> roles;
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public Instant getExpiresAt() {
+        return expiresAt;
+    }
+
+    public void setExpiresAt(Instant expiresAt) {
+        this.expiresAt = expiresAt;
+    }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public List<String> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<String> roles) {
+        this.roles = roles;
+    }
+}
diff --git a/backend/demo/src/main/java/com/example/demo/entity/User.java b/backend/demo/src/main/java/com/example/demo/entity/User.java
new file mode 100644
index 0000000..bcbe6de
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/entity/User.java
@@ -0,0 +1,105 @@
+package com.example.demo.entity;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+
+@TableName("user")
+public class User implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    private String username;
+
+    private String password;
+
+    private String email;
+
+    private Integer status; 
+
+    private Integer score; 
+
+    private String role; 
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Integer getScore() {
+        return score;
+    }
+
+    public void setScore(Integer score) {
+        this.score = score;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    public LocalDateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(LocalDateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+}
diff --git a/backend/demo/src/main/java/com/example/demo/exception/AuthException.java b/backend/demo/src/main/java/com/example/demo/exception/AuthException.java
new file mode 100644
index 0000000..526f1da
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/exception/AuthException.java
@@ -0,0 +1,14 @@
+package com.example.demo.exception;
+
+/**
+ * 自定义认证/授权异常
+ */
+public class AuthException extends RuntimeException {
+    public AuthException(String message) {
+        super(message);
+    }
+
+    public AuthException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/backend/demo/src/main/java/com/example/demo/exception/GlobalExceptionHandler.java b/backend/demo/src/main/java/com/example/demo/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..bc560e6
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/exception/GlobalExceptionHandler.java
@@ -0,0 +1,39 @@
+package com.example.demo.exception;
+
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@ControllerAdvice
+public class GlobalExceptionHandler {
+
+    /** 处理自定义认证异常 */
+    @ExceptionHandler(AuthException.class)
+    public ResponseEntity<Map<String, String>> handleAuthException(AuthException ex) {
+        Map<String, String> body = Map.of("error", ex.getMessage());
+        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(body);
+    }
+
+    /** 处理请求参数校验失败 */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
+        Map<String, String> errors = new HashMap<>();
+        for (FieldError fe : ex.getBindingResult().getFieldErrors()) {
+            errors.put(fe.getField(), fe.getDefaultMessage());
+        }
+        return ResponseEntity.badRequest().body(errors);
+    }
+
+    /** 处理其它未捕获的异常 */
+    @ExceptionHandler(Exception.class)
+    public ResponseEntity<Map<String, String>> handleAllExceptions(Exception ex) {
+        Map<String, String> body = Map.of("error", "Internal server error");
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(body);
+    }
+}
diff --git a/backend/demo/src/main/java/com/example/demo/mapper/UserMapper.java b/backend/demo/src/main/java/com/example/demo/mapper/UserMapper.java
new file mode 100644
index 0000000..94ba7a8
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/mapper/UserMapper.java
@@ -0,0 +1,17 @@
+package com.example.demo.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.example.demo.entity.User;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * UserMapper 接口
+ * 
+ * 继承 MyBatis-Plus 提供的 BaseMapper,实现基本的 CRUD 操作
+ */
+@Mapper
+public interface UserMapper extends BaseMapper<User> {
+    
+    // List<User> selectByStatus(@Param("status") Integer status);
+}
+
diff --git a/backend/demo/src/main/java/com/example/demo/security/JwtAuthenticationFilter.java b/backend/demo/src/main/java/com/example/demo/security/JwtAuthenticationFilter.java
new file mode 100644
index 0000000..108e966
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/security/JwtAuthenticationFilter.java
@@ -0,0 +1,64 @@
+package com.example.demo.security;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import com.example.demo.config.JWTProperties;
+import com.example.demo.exception.AuthException;
+
+import io.jsonwebtoken.Claims;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+@Component 
+public class JwtAuthenticationFilter extends OncePerRequestFilter {
+
+    private final JwtTokenUtil tokenUtil;
+    private final JWTProperties props;
+
+    public JwtAuthenticationFilter(JwtTokenUtil tokenUtil, JWTProperties props) {
+        this.tokenUtil = tokenUtil;
+        this.props = props;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
+
+        String headerValue = request.getHeader(props.getHeader());
+        if (!StringUtils.hasText(headerValue) || !headerValue.startsWith(props.getTokenPrefix())) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        String token = headerValue.substring(props.getTokenPrefix().length());
+        if (!tokenUtil.validateToken(token)) {
+            throw new AuthException("Invalid or expired JWT token");
+        }
+
+        Claims claims = tokenUtil.parseClaims(token);
+        String username = claims.getSubject();
+        Long userId = tokenUtil.getUserId(token);
+        String role = tokenUtil.getRole(token);
+
+        UsernamePasswordAuthenticationToken auth =
+            new UsernamePasswordAuthenticationToken(
+                userId, 
+                null, 
+                List.of(new SimpleGrantedAuthority(role))
+            );
+        SecurityContextHolder.getContext().setAuthentication(auth);
+
+        chain.doFilter(request, response);
+    }
+}
diff --git a/backend/demo/src/main/java/com/example/demo/security/JwtTokenUtil.java b/backend/demo/src/main/java/com/example/demo/security/JwtTokenUtil.java
new file mode 100644
index 0000000..3f44d8a
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/security/JwtTokenUtil.java
@@ -0,0 +1,81 @@
+package com.example.demo.security;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.Map;
+
+import org.springframework.stereotype.Component;
+
+import com.example.demo.config.JWTProperties;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
+@Component
+public class JwtTokenUtil {
+
+    private final JWTProperties props;
+    private final byte[] secretBytes;
+
+    public JwtTokenUtil(JWTProperties props) {
+        this.props = props;
+        this.secretBytes = props.getSecret().getBytes(StandardCharsets.UTF_8);
+    }
+
+    /** 生成 JWT */
+    public String generateToken(Long userId, String username, String role) {
+        Date now = new Date();
+        Date expiry = new Date(now.getTime() + props.getExpirationMs());
+
+        return Jwts.builder()
+                .setSubject(username)
+                .setIssuer(props.getIssuer())
+                .setAudience(props.getAudience())
+                .setIssuedAt(now)
+                .setExpiration(expiry)
+                .addClaims(Map.of("userId", userId, "role", role))
+                .signWith(Keys.hmacShaKeyFor(secretBytes), SignatureAlgorithm.HS256)
+                .compact();
+    }
+
+    /** 验证并解析 Token,抛出异常则验证失败 */
+    public Claims parseClaims(String token) {
+        return Jwts.parserBuilder()
+                .setSigningKey(secretBytes)
+                .build()
+                .parseClaimsJws(token)
+                .getBody();
+    }
+
+    /** 校验 Token 是否有效 */
+    public boolean validateToken(String token) {
+        try {
+            parseClaims(token);
+            return true;
+        } catch (JwtException e) {
+            return false;
+        }
+    }
+
+    /** 从 Token 获取用户名(Subject) */
+    public String getUsername(String token) {
+        return parseClaims(token).getSubject();
+    }
+
+    /** 从 Token 获取用户 ID */
+    public Long getUserId(String token) {
+        Object id = parseClaims(token).get("userId");
+        return id == null ? null : Long.valueOf(id.toString());
+    }
+
+    /** 从 Token 获取角色 */
+    public String getRole(String token) {
+        return parseClaims(token).get("role", String.class);
+    }
+
+    public long getExpiration() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
diff --git a/backend/demo/src/main/java/com/example/demo/service/UserService.java b/backend/demo/src/main/java/com/example/demo/service/UserService.java
new file mode 100644
index 0000000..60e8aef
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/service/UserService.java
@@ -0,0 +1,13 @@
+package com.example.demo.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.demo.entity.User;
+
+/**
+ * User 业务层接口
+ */
+public interface UserService extends IService<User> {
+    // 如果需要自定义方法,可以在这里再添加,例如:
+    // User findByUsername(String username);
+}
diff --git a/backend/demo/src/main/java/com/example/demo/service/impl/UserServiceImpl.java b/backend/demo/src/main/java/com/example/demo/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..5bd1693
--- /dev/null
+++ b/backend/demo/src/main/java/com/example/demo/service/impl/UserServiceImpl.java
@@ -0,0 +1,23 @@
+package com.example.demo.service.impl;
+
+// UserServiceImpl.java
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.demo.entity.User;
+import com.example.demo.mapper.UserMapper;
+import com.example.demo.service.UserService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * User 业务层默认实现
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
+    // 如果你在接口中声明了自定义方法,这里可以重写并实现:
+    // @Override
+    // public User findByUsername(String username) {
+    //     return lambdaQuery().eq(User::getUsername, username).one();
+    // }
+}
diff --git a/backend/demo/src/main/resources/application.properties b/backend/demo/src/main/resources/application.properties
index 90968f5..4472028 100644
--- a/backend/demo/src/main/resources/application.properties
+++ b/backend/demo/src/main/resources/application.properties
@@ -1,10 +1,12 @@
-# H2 Configuration (Ensure these are uncommented)
-spring.datasource.url=jdbc:h2:mem:testdb
-spring.datasource.driver-class-name=org.h2.Driver
-spring.datasource.username=sa
-spring.datasource.password=
-spring.h2.console.enabled=true
+# ========== 数据源 ==========
+spring.datasource.url=jdbc:mysql://mysql:3306/mydatabase?serverTimezone=Asia/Shanghai
+spring.datasource.username=myuser
+spring.datasource.password=secret
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 
-# Required for JPA/Hibernate
-spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
-spring.jpa.hibernate.ddl-auto=update
\ No newline at end of file
+# ========== JWT 配置 ==========
+jwt.secret=YourJWTSecretKeyHere1234567890
+jwt.expirationMs=3600000
+
+# ========== 日志输出(可选) ==========
+logging.level.org.springframework.security=DEBUG