getSupportedMediaTypes() {
+ return Collections.singletonList(MediaType.APPLICATION_JSON_UTF8);
+ }
+ });
+
+
+ }
+}
diff --git a/src/main/java/com/sczx/user/constant/SystemConstants.java b/src/main/java/com/sczx/user/constant/SystemConstants.java
new file mode 100644
index 0000000..52f3ead
--- /dev/null
+++ b/src/main/java/com/sczx/user/constant/SystemConstants.java
@@ -0,0 +1,23 @@
+package com.sczx.user.constant;
+
+
+/**
+ * 应用模块名称
+ *
+ * 代码描述
+ *
+ * Copyright: Copyright (C) 2022 CD Finance Management Co., Ltd. All rights reserved.
+ *
+ * Company: 中和农信项目管理有限公司
+ *
+ * @author zhonghui
+ * @since 2022/4/1 3:33 PM
+ */
+public interface SystemConstants {
+
+ /***
+ * feign客户端所在包路径
+ */
+ String FEIGN_CLIENT_BASE_PACKAGE = "com.sczx.app.thirdpart.facade";
+
+}
diff --git a/src/main/java/com/sczx/user/controller/AuthController.java b/src/main/java/com/sczx/user/controller/AuthController.java
new file mode 100644
index 0000000..91b9fdd
--- /dev/null
+++ b/src/main/java/com/sczx/user/controller/AuthController.java
@@ -0,0 +1,37 @@
+package com.sczx.user.controller;
+
+import com.sczx.user.model.LoginRequest;
+import com.sczx.user.service.IUserService;
+import com.sczx.user.util.JwtUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+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;
+
+@Tag(name = "登录控制器", description = "注册、登录")
+@RequestMapping("/auth")
+@RestController
+public class AuthController {
+
+ @Autowired
+ private IUserService userService;
+ @Autowired
+ private JwtUtil jwtUtil;
+
+ @Operation(summary = "注册", description = "用户注册")
+ @PostMapping("/register")
+ public ResponseEntity register(@RequestBody LoginRequest request) {
+ return ResponseEntity.ok(userService.register(request));
+ }
+
+ @Operation(summary = "登录", description = "用户登录返回token")
+ @PostMapping("/login")
+ public ResponseEntity login(@RequestBody LoginRequest request) {
+ String token = userService.login(request);
+ return ResponseEntity.ok(token);
+ }
+}
diff --git a/src/main/java/com/sczx/user/controller/DemoController.java b/src/main/java/com/sczx/user/controller/DemoController.java
new file mode 100644
index 0000000..b57d580
--- /dev/null
+++ b/src/main/java/com/sczx/user/controller/DemoController.java
@@ -0,0 +1,16 @@
+package com.sczx.user.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@Tag(name = "示例接口", description = "用于演示 Springdoc 的接口")
+public class DemoController {
+ @GetMapping("/test")
+ @Operation(summary = "测试接口", description = "返回一个测试字符串")
+ public String test() {
+ return "OK";
+ }
+}
diff --git a/src/main/java/com/sczx/user/model/LoginRequest.java b/src/main/java/com/sczx/user/model/LoginRequest.java
new file mode 100644
index 0000000..1045ed3
--- /dev/null
+++ b/src/main/java/com/sczx/user/model/LoginRequest.java
@@ -0,0 +1,23 @@
+package com.sczx.user.model;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.Data;
+
+/**
+ * @Author: 张黎
+ * @Date: 2025/07/06/13:41
+ * @Description:
+ */
+@Schema(description = "用户注册请求")
+@Data
+public class LoginRequest {
+ @Schema(description = "用户名")
+ private String username;
+ @Schema(description = "密码")
+ private String password;
+ @Schema(description = "微信登录 code")
+ private String wechatCode; // 微信登录 code
+ @Schema(description = "支付宝 user_id")
+ private String alipayUserId; // 支付宝 user_id
+}
\ No newline at end of file
diff --git a/src/main/java/com/sczx/user/model/LoginResponse.java b/src/main/java/com/sczx/user/model/LoginResponse.java
new file mode 100644
index 0000000..648594d
--- /dev/null
+++ b/src/main/java/com/sczx/user/model/LoginResponse.java
@@ -0,0 +1,21 @@
+package com.sczx.user.model;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * @Author: 张黎
+ * @Date: 2025/07/06/13:57
+ * @Description:
+ */
+
+@Schema(description = "登录返回")
+@Data
+public class LoginResponse {
+ @Schema(description = "登录的token")
+ private String token;
+ @Schema(description = "登录的refreshToken")
+ private String refreshToken;
+ @Schema(description = "登录用户的角色")
+ private String role;
+}
\ No newline at end of file
diff --git a/src/main/java/com/sczx/user/service/IUserService.java b/src/main/java/com/sczx/user/service/IUserService.java
new file mode 100644
index 0000000..bbe0f77
--- /dev/null
+++ b/src/main/java/com/sczx/user/service/IUserService.java
@@ -0,0 +1,25 @@
+package com.sczx.user.service;
+
+import com.sczx.user.model.LoginRequest;
+
+/**
+ * @Author: 张黎
+ * @Date: 2025/07/06/14:27
+ * @Description:
+ */
+public interface IUserService {
+
+ /**
+ * 用户注册
+ * @param request
+ * @return
+ */
+ String register(LoginRequest request);
+
+ /**
+ * 用户登录
+ * @param request
+ * @return
+ */
+ String login(LoginRequest request);
+}
diff --git a/src/main/java/com/sczx/user/service/impl/UserServiceImpl.java b/src/main/java/com/sczx/user/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..62887d8
--- /dev/null
+++ b/src/main/java/com/sczx/user/service/impl/UserServiceImpl.java
@@ -0,0 +1,60 @@
+package com.sczx.user.service.impl;
+
+import com.sczx.user.model.LoginRequest;
+import com.sczx.user.service.IUserService;
+import com.sczx.user.util.JwtUtil;
+import com.sczx.user.util.RedisUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Author: 张黎
+ * @Date: 2025/07/06/14:28
+ * @Description:
+ */
+@Slf4j
+@Service
+public class UserServiceImpl implements IUserService {
+
+ @Autowired
+ private JwtUtil jwtUtil;
+
+ @Autowired
+ private RedisUtil redisUtil;
+ @Override
+ public String register(LoginRequest request) {
+ log.info("用户注册信息:{}", request);
+ // TODO: 2025/07/06 用户注册逻辑
+// if (userRepository.existsByUsername(request.getUsername())) {
+// throw new RuntimeException("用户名已存在");
+// }
+//
+// User user = new User();
+// user.setUsername(request.getUsername());
+// user.setPassword(passwordEncoder.encode(request.getPassword()));
+// user.setRole("USER");
+//
+// userRepository.save(user);
+ return "用户注册成功";
+ }
+
+ @Override
+ public String login(LoginRequest request) {
+// User user = userRepository.findByUsername(request.getUsername())
+// .orElseThrow(() -> new RuntimeException("用户名或密码错误"));
+//
+// if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
+// throw new RuntimeException("密码错误");
+// }
+
+ String token = jwtUtil.generateToken(request.getUsername(), "user.role");
+
+ // 存入 Redis
+ redisUtil.set("token:" + request.getUsername(), token, 24, TimeUnit.HOURS);
+
+ return token;
+ }
+}
diff --git a/src/main/java/com/sczx/user/util/ComputerInfo.java b/src/main/java/com/sczx/user/util/ComputerInfo.java
new file mode 100644
index 0000000..2e86f82
--- /dev/null
+++ b/src/main/java/com/sczx/user/util/ComputerInfo.java
@@ -0,0 +1,159 @@
+package com.sczx.user.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/*
+ * <取网卡物理地址--
+ * 1.在Windows,Linux系统下均可用;
+ * 2.通过ipconifg,ifconfig获得计算机信息;
+ * 3.再用模式匹配方式查找MAC地址,与操作系统的语言无关>
+ *
+ * //* Description: <取计算机名--从环境变量中取>
+ * abstract 限制继承/创建实例
+ */
+public abstract class ComputerInfo {
+ private static String macAddressStr = null;
+ private static String computerName = System.getenv().get("COMPUTERNAME");
+
+ private static final String[] windowsCommand = { "ipconfig", "/all" };
+ private static final String[] linuxCommand = { "/sbin/ifconfig", "-a" };
+ private static final String[] macCommand = { "ifconfig", "-a" };
+ private static final Pattern macPattern = Pattern.compile(".*((:?[0-9a-f]{2}[-:]){5}[0-9a-f]{2}).*",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * 获取多个网卡地址
+ *
+ * @return
+ * @throws IOException
+ */
+ private final static List getMacAddressList() throws IOException {
+ final ArrayList macAddressList = new ArrayList();
+ final String os = System.getProperty("os.name");
+ final String command[];
+
+ if (os.startsWith("Windows")) {
+ command = windowsCommand;
+ } else if (os.startsWith("Linux")) {
+ command = linuxCommand;
+ } else if (os.startsWith("Mac")){
+ command = macCommand;
+ }
+ else {
+ throw new IOException("Unknow operating system:" + os);
+ }
+ // 执行命令
+ final Process process = Runtime.getRuntime().exec(command);
+
+ BufferedReader bufReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ for (String line = null; (line = bufReader.readLine()) != null;) {
+ Matcher matcher = macPattern.matcher(line);
+ if (matcher.matches()) {
+ macAddressList.add(matcher.group(1));
+ // macAddressList.add(matcher.group(1).replaceAll("[-:]",
+ // ""));//去掉MAC中的“-”
+ }
+ }
+
+ process.destroy();
+ bufReader.close();
+ return macAddressList;
+ }
+
+ /**
+ * 获取一个网卡地址(多个网卡时从中获取一个)
+ *
+ * @return
+ */
+ public static String getMacAddress() {
+ if (macAddressStr == null || macAddressStr.equals("")) {
+ StringBuffer sb = new StringBuffer(); // 存放多个网卡地址用,目前只取一个非0000000000E0隧道的值
+ try {
+ List macList = getMacAddressList();
+ for (Iterator iter = macList.iterator(); iter.hasNext();) {
+ String amac = iter.next();
+ if (!"0000000000E0".equals(amac)) {
+ sb.append(amac);
+ break;
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ macAddressStr = sb.toString();
+
+ }
+
+ return macAddressStr;
+ }
+
+ /**
+ * 获取电脑名
+ *
+ * @return
+ */
+ public static String getComputerName() {
+ if (computerName == null || computerName.equals("")) {
+ computerName = System.getenv().get("COMPUTERNAME");
+ }
+ return computerName;
+ }
+
+ /**
+ * 获取客户端IP地址
+ *
+ * @return
+ */
+ public static String getIpAddrAndName() throws IOException {
+ return InetAddress.getLocalHost().toString();
+ }
+
+ /**
+ * 获取客户端IP地址
+ *
+ * @return
+ */
+ public static String getIpAddr() throws IOException {
+ return InetAddress.getLocalHost().getHostAddress().toString();
+ }
+
+ /**
+ * 获取电脑唯一标识
+ *
+ * @return
+ */
+ public static String getComputerID() {
+ String id = getMacAddress();
+ if (id == null || id.equals("")) {
+ try {
+ id = getIpAddrAndName();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return computerName;
+ }
+
+ /**
+ * 限制创建实例
+ */
+ private ComputerInfo() {
+
+ }
+
+ public static void main(String[] args) throws IOException {
+ System.out.println(ComputerInfo.getMacAddress());
+ System.out.println(ComputerInfo.getComputerName());
+ System.out.println(ComputerInfo.getIpAddr());
+ System.out.println(ComputerInfo.getIpAddrAndName());
+ }
+}
diff --git a/src/main/java/com/sczx/user/util/JwtUtil.java b/src/main/java/com/sczx/user/util/JwtUtil.java
new file mode 100644
index 0000000..5058bbb
--- /dev/null
+++ b/src/main/java/com/sczx/user/util/JwtUtil.java
@@ -0,0 +1,63 @@
+package com.sczx.user.util;
+
+import io.jsonwebtoken.JwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.SecretKey;
+import java.util.Date;
+
+/**
+ * @Author: 张黎
+ * @Date: 2025/07/06/14:00
+ * @Description:
+ */
+@Slf4j
+@Component
+public class JwtUtil {
+
+ @Value("${auth.token-expiration}")
+ private long expiration;
+ private final SecretKey key;
+
+ public JwtUtil(@Value("${auth.secret-key}") String secretKey) {
+ this.key = Keys.hmacShaKeyFor(secretKey.getBytes());
+
+// this.key = Keys.secretKeyFor(SignatureAlgorithm.HS512);
+ log.info("JWT 密钥:{}", secretKey);
+ }
+
+ public String generateToken(String username, String role) {
+ return Jwts.builder()
+ .setSubject(username)
+ .claim("role", role)
+ .setExpiration(new Date(System.currentTimeMillis() + expiration))
+ .signWith(key, SignatureAlgorithm.HS512)
+ .compact();
+ }
+
+ public String extractUsername(String token) {
+ return Jwts.parserBuilder()
+ .setSigningKey(key)
+ .build()
+ .parseClaimsJws(token)
+ .getBody()
+ .getSubject();
+ }
+
+ public boolean validateToken(String token) {
+ try {
+ Jwts.parserBuilder()
+ .setSigningKey(key)
+ .build()
+ .parseClaimsJws(token);
+ return true;
+ } catch (JwtException ex) {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/com/sczx/user/util/RedisUtil.java b/src/main/java/com/sczx/user/util/RedisUtil.java
new file mode 100644
index 0000000..1ab98cc
--- /dev/null
+++ b/src/main/java/com/sczx/user/util/RedisUtil.java
@@ -0,0 +1,34 @@
+package com.sczx.user.util;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Author: 张黎
+ * @Date: 2025/07/06/14:21
+ * @Description:
+ */
+@Component
+public class RedisUtil {
+
+
+ @Autowired
+ private StringRedisTemplate redisTemplate;
+
+ public void set(String key, String value, long timeout, TimeUnit unit) {
+ redisTemplate.opsForValue().set(key, value, timeout, unit);
+ }
+
+ public String get(String key) {
+ return redisTemplate.opsForValue().get(key);
+ }
+
+ public void delete(String key) {
+ redisTemplate.delete(key);
+ }
+
+}
diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml
new file mode 100644
index 0000000..ee418b6
--- /dev/null
+++ b/src/main/resources/application-local.yml
@@ -0,0 +1,29 @@
+#本地开发
+spring:
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 115.190.8.52:8848 # Nacos 地址
+ group: DEFAULT_GROUP
+ metadata:
+ version: 1.0.0
+ env: dev
+
+ datasource:
+ url: jdbc:mysql://115.190.8.52:3306/sczx?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
+ username: sczx_user
+ password: Sczx123@
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ hikari:
+ maximum-pool-size: 10
+ auto-commit: true
+ redis:
+ host: 115.190.8.52
+ port: 6379
+ lettuce:
+ pool:
+ max-active: 8
+ max-wait: 2000ms
+ max-idle: 4
+ min-idle: 1
+ max-life-time: 300000ms
\ No newline at end of file
diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml
new file mode 100644
index 0000000..18eb6e7
--- /dev/null
+++ b/src/main/resources/application-test.yml
@@ -0,0 +1,28 @@
+#远程测试部署
+spring:
+ cloud:
+ nacos:
+ discovery:
+ server-addr: localhost:8848 # Nacos 地址
+ group: DEFAULT_GROUP
+ metadata:
+ version: 1.0.0
+ env: dev
+ datasource:
+ url: jdbc:mysql://localhost:3306/sczx?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
+ username: sczx_user
+ password: Sczx123@
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ hikari:
+ maximum-pool-size: 10
+ auto-commit: true
+ redis:
+ host: localhost
+ port: 6379
+ lettuce:
+ pool:
+ max-active: 8
+ max-wait: 2000ms
+ max-idle: 4
+ min-idle: 1
+ max-life-time: 300000ms
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..7d8a02a
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,76 @@
+
+server:
+ port: 8081
+
+spring:
+ application:
+ name: sczx_user # 微服务名称
+ http:
+ encoding:
+ charset: UTF-8
+ enabled: true
+ force: true
+ mvc:
+ async:
+ request-timeout: -1
+#
+# cloud:
+# nacos:
+# discovery:
+# server-addr: 115.190.8.52:8848 # Nacos 地址
+# group: DEFAULT_GROUP
+# metadata:
+# version: 1.0.0
+# env: dev
+
+ jpa:
+ hibernate:
+ ddl-auto: update
+ show-sql: true
+ database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
+
+ lifecycle:
+ timeout-per-shutdown-phase: 30s # 设置优雅停机时间
+
+management:
+ endpoints:
+ web:
+ exposure:
+ include: "*" # 暴露所有监控端点
+ endpoint:
+ health:
+ show-details: always
+
+feign:
+ client:
+ config:
+ default:
+ connectTimeout: 5000
+ readTimeout: 5000
+ hystrix:
+ enabled: true # 启用 Feign 的 Hystrix 支持
+
+hystrix:
+ command:
+ default:
+ execution:
+ isolation:
+ thread:
+ timeoutInMilliseconds: 10000 # 默认熔断超时时间
+
+springdoc:
+ swagger-ui:
+ url: /v3/api-docs
+ path: /doc.html
+ packages-to-scan: com.sczx.user.controller # 替换为你的 controller 包路径
+
+mybatis-plus:
+ mapper-locations: classpath*:mapper/**/*.xml
+ type-aliases-package: com.sczx.user.entity # 实体类包路径
+ configuration:
+ mapUnderscoreToCamelCase: true
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印 SQL(调试用)
+
+auth:
+ secret-key: his-is-a-very-long-and-secure-secret-key-for-jwt-signing-please-dont-use-short-keys
+ token-expiration: 86400000 # 24小时
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
new file mode 100644
index 0000000..e594345
--- /dev/null
+++ b/src/main/resources/logback.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+ ${PATTERN}
+
+
+
+
+
+ ${LOG_FILE_PATH}/${hostname}/info.%d{yyyy-MM-dd}.log
+ 31
+
+
+
+ ${PATTERN}
+
+
+
+ WARN
+ DENY
+ NEUTRAL
+
+
+ ERROR
+ DENY
+ NEUTRAL
+
+
+
+
+
+ WARN
+
+ ${LOG_FILE_PATH}/${hostname}/warn.log
+ true
+
+ ${PATTERN}
+
+
+
+
+
+
+
+
+
\ No newline at end of file