From e14caf654a6e5d01a0b2fd43372ab94eb983ab16 Mon Sep 17 00:00:00 2001 From: zhangli <123879394@qq.com> Date: Sun, 6 Jul 2025 15:18:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E5=8F=8A=E7=99=BB=E5=BD=95=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E5=90=8E=E7=BB=AD=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 53 ++-- Dockerfile | 10 + Jenkinsfile | 78 +++++ pom.xml | 292 ++++++++++++++++++ src/main/java/com/sczx/user/Application.java | 34 ++ .../sczx/user/config/MyBatisPlusConfig.java | 18 ++ .../com/sczx/user/config/SpringDocConfig.java | 16 + .../java/com/sczx/user/config/WebConfig.java | 44 +++ .../sczx/user/constant/SystemConstants.java | 23 ++ .../sczx/user/controller/AuthController.java | 37 +++ .../sczx/user/controller/DemoController.java | 16 + .../com/sczx/user/model/LoginRequest.java | 23 ++ .../com/sczx/user/model/LoginResponse.java | 21 ++ .../com/sczx/user/service/IUserService.java | 25 ++ .../user/service/impl/UserServiceImpl.java | 60 ++++ .../java/com/sczx/user/util/ComputerInfo.java | 159 ++++++++++ src/main/java/com/sczx/user/util/JwtUtil.java | 63 ++++ .../java/com/sczx/user/util/RedisUtil.java | 34 ++ src/main/resources/application-local.yml | 29 ++ src/main/resources/application-test.yml | 28 ++ src/main/resources/application.yml | 76 +++++ src/main/resources/logback.xml | 53 ++++ 22 files changed, 1170 insertions(+), 22 deletions(-) create mode 100644 Dockerfile create mode 100644 Jenkinsfile create mode 100644 pom.xml create mode 100644 src/main/java/com/sczx/user/Application.java create mode 100644 src/main/java/com/sczx/user/config/MyBatisPlusConfig.java create mode 100644 src/main/java/com/sczx/user/config/SpringDocConfig.java create mode 100644 src/main/java/com/sczx/user/config/WebConfig.java create mode 100644 src/main/java/com/sczx/user/constant/SystemConstants.java create mode 100644 src/main/java/com/sczx/user/controller/AuthController.java create mode 100644 src/main/java/com/sczx/user/controller/DemoController.java create mode 100644 src/main/java/com/sczx/user/model/LoginRequest.java create mode 100644 src/main/java/com/sczx/user/model/LoginResponse.java create mode 100644 src/main/java/com/sczx/user/service/IUserService.java create mode 100644 src/main/java/com/sczx/user/service/impl/UserServiceImpl.java create mode 100644 src/main/java/com/sczx/user/util/ComputerInfo.java create mode 100644 src/main/java/com/sczx/user/util/JwtUtil.java create mode 100644 src/main/java/com/sczx/user/util/RedisUtil.java create mode 100644 src/main/resources/application-local.yml create mode 100644 src/main/resources/application-test.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/logback.xml diff --git a/.gitignore b/.gitignore index 9154f4c..0d7f4db 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,35 @@ -# ---> Java -# Compiled class file -*.class +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ -# Log file -*.log +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache -# BlueJ files -*.ctxt +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -replay_pid* +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ +### VS Code ### +.vscode/ +logs/ +src/main/resources/rebel.xml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..98717d8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +# 使用 OpenJDK 8 镜像构建 +FROM openjdk:8-jdk +# 添加作者信息 +LABEL maintainer="123879394@qq.com" + +WORKDIR /app +# 复制 jar 包 +COPY target/*.jar app.jar +# 设置 JVM 参数和启动命令 +ENTRYPOINT ["java", "-jar", "-Xms128m", "-Xmx256m", "app.jar"] \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..b313da6 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,78 @@ +pipeline { + agent any + tools { + maven 'M3' // 必须在 Jenkins → Manage Jenkins → Global Tool Configuration 中配置过 + } + environment { + APP_NAME = "sczx_user" + DOCKER_IMAGE = "${APP_NAME}:latest" + CONTAINER_NAME = "${APP_NAME}-container" + } + + stages { + stage('Checkout') { + steps { + echo "📦 正在拉取代码..." + git branch: 'main', url: 'http://115.190.8.52:3000/sczx_group/sczx_user.git' + } + } + + stage('Build with Maven') { + steps { + echo "🛠️ 正在使用 Maven 构建..." + sh 'mvn clean package -s settings.xml' + } + } + + stage('Check Jar File') { + steps { + sh 'ls -la target/' // 确保 jar 文件存在 + } + } + + stage('Build Docker Image') { + steps { + echo "🐋 正在构建 Docker 镜像..." + sh """ + docker build -t \${DOCKER_IMAGE} . + """ + } + } + + stage('Stop Old Container') { + steps { + echo "🛑 正在停止旧的容器(如果存在)..." + sh ''' + if [ "$(docker ps -f 'name=sczx_user-container' --format '{{.Status}}')" ]; then + docker stop sczx_user-container + docker rm sczx_user-container + fi + ''' + } + } + + stage('Run New Container') { + steps { + echo "🟢 正在运行新的容器..." + sh """ + docker run -d \ + --name \${CONTAINER_NAME} \ + -p 8081:8081 \ + -e SPRING_PROFILES_ACTIVE=test \ + -e JAVA_OPTS="-Xms256m -Xmx512m -Duser.timezone=Asia/Shanghai" \ + --restart always \ + \${DOCKER_IMAGE} + """ + } + } + } + + post { + success { + echo "🎉 构建成功!" + } + failure { + echo "❌ 构建失败,请检查日志!" + } + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..29884dc --- /dev/null +++ b/pom.xml @@ -0,0 +1,292 @@ + + + 4.0.0 + + com.sczx + sczx_user + 1.0.0 + jar + + sczx_user + sczx_user service + + + 1.8 + 2.3.12.RELEASE + Hoxton.SR12 + 2.2.9.RELEASE + + + + + org.springframework.boot + spring-boot-starter-parent + 2.3.12.RELEASE + + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring-cloud-alibaba.version} + pom + import + + + + + + + + + org.springframework.boot + spring-boot-starter + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + org.springframework.cloud + spring-cloud-commons + + + + + org.projectlombok + lombok + 1.18.30 + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + + + org.springframework.retry + spring-retry + 1.3.1 + + + + org.springframework.boot + spring-boot-starter-aop + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.3.1 + + + + + com.baomidou + mybatis-plus-boot-starter + 3.5.3.1 + + + + + com.baomidou + mybatis-plus-generator + 3.5.1 + + + + + org.freemarker + freemarker + 2.3.31 + + + + + mysql + mysql-connector-java + 8.0.33 + + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + + + + + + + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.apache.commons + commons-pool2 + 2.11.1 + + + + + org.springdoc + springdoc-openapi-ui + 1.6.14 + + + + org.webjars + swagger-ui + 4.15.5 + + + + + javax.xml.bind + jaxb-api + 2.3.1 + + + + io.projectreactor + reactor-core + 3.2.2.RELEASE + + + + + + sczx_user + + + src/main/resources + + *.yml + + true + + + src/main/resources + + *.yml + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.6.0 + + + unpack + process-resources + + unpack + + + + + org.webjars + swagger-ui + 4.15.5 + jar + ${project.build.outputDirectory} + META-INF/resources/** + + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + + \ No newline at end of file diff --git a/src/main/java/com/sczx/user/Application.java b/src/main/java/com/sczx/user/Application.java new file mode 100644 index 0000000..01e45ce --- /dev/null +++ b/src/main/java/com/sczx/user/Application.java @@ -0,0 +1,34 @@ +package com.sczx.user; + + +import com.sczx.user.constant.SystemConstants; +import com.sczx.user.util.ComputerInfo; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.hystrix.EnableHystrix; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.retry.annotation.EnableRetry; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.io.IOException; + +@SpringBootApplication +@EnableDiscoveryClient // 启用服务注册与发现 +@EnableRetry +@EnableFeignClients(basePackages = SystemConstants.FEIGN_CLIENT_BASE_PACKAGE ) +@EnableTransactionManagement +@EnableHystrix +@MapperScan("com.sczx.user.mapper") // 扫描 Mapper 接口 +public class Application { + + public static void main(String[] args) throws IOException { + ConfigurableApplicationContext context = SpringApplication.run(Application.class, args); + Environment environment = context.getBean(Environment.class); + System.out.println("启动成功,后端服务API地址:http://" + ComputerInfo.getIpAddr() + ":" + + environment.getProperty("server.port") + "/doc.html"); + } +} diff --git a/src/main/java/com/sczx/user/config/MyBatisPlusConfig.java b/src/main/java/com/sczx/user/config/MyBatisPlusConfig.java new file mode 100644 index 0000000..6b99072 --- /dev/null +++ b/src/main/java/com/sczx/user/config/MyBatisPlusConfig.java @@ -0,0 +1,18 @@ +package com.sczx.user.config; + +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()); + return interceptor; + } +} diff --git a/src/main/java/com/sczx/user/config/SpringDocConfig.java b/src/main/java/com/sczx/user/config/SpringDocConfig.java new file mode 100644 index 0000000..9428737 --- /dev/null +++ b/src/main/java/com/sczx/user/config/SpringDocConfig.java @@ -0,0 +1,16 @@ +package com.sczx.user.config; + + +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; + +//@Configuration +public class SpringDocConfig { + @Bean + public GroupedOpenApi publicApi() { + return GroupedOpenApi.builder() + .group("sczx-service") + .packagesToScan("com.sczx.app.controller") + .build(); + } +} diff --git a/src/main/java/com/sczx/user/config/WebConfig.java b/src/main/java/com/sczx/user/config/WebConfig.java new file mode 100644 index 0000000..404a05d --- /dev/null +++ b/src/main/java/com/sczx/user/config/WebConfig.java @@ -0,0 +1,44 @@ +package com.sczx.user.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; + +@Configuration +@EnableWebMvc +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/swagger-ui/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/swagger-ui/4.15.5/"); + registry.addResourceHandler("/swagger-ui.html") + .addResourceLocations("classpath:/META-INF/resources/swagger-ui.html"); + registry.addResourceHandler("/v3/api-docs/**") + .addResourceLocations("classpath:/META-INF/resources/swagger-ui/"); + } + + @Override + public void configureMessageConverters(List> converters) { + + converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8)); + // 添加支持 application/json;charset=UTF-8 的 Jackson 转换器 + converters.add(new MappingJackson2HttpMessageConverter() { + @Override + public List 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