初始化车辆车型套餐服务

This commit is contained in:
2025-07-12 00:13:44 +08:00
commit d8b738ff93
22 changed files with 1379 additions and 0 deletions

View File

@ -0,0 +1,34 @@
package com.sczx.car;
import com.sczx.car.constant.SystemConstants;
import com.sczx.car.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.store.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") + "/swagger-ui.html");
}
}

View File

@ -0,0 +1,12 @@
package com.sczx.car.common;
/**
* @Author: 张黎
* @Date: 2025/07/09/20:20
* @Description:
*/
public interface IApiCode {
String getCode();
String getMsg();
}

View File

@ -0,0 +1,121 @@
package com.sczx.car.common;
import com.sczx.car.common.enums.ApiErrorCode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: 张黎
* @Date: 2025/07/09/20:25
* @Description:
*/
@ApiModel(value = "公共返回结果")
@Builder
@Data
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1331134667810352183L;
@ApiModelProperty(value = "成功标识")
private boolean success;
@ApiModelProperty(value = "返回编码")
private String code;
@ApiModelProperty(value = "返回信息说明")
private String msg;
private String issue;
@ApiModelProperty(value = "返回数据")
private T data;
public Result(boolean success, String code, String msg, String issue, T data) {
this.success = success;
this.code = code;
this.msg = msg;
this.issue = issue;
this.data = data;
}
public static Result result(IApiCode apiCode) {
return result(apiCode, (Object)null);
}
public static Result result(IApiCode apiCode, Object data) {
return result(apiCode, apiCode.getMsg(), data);
}
public static Result result(IApiCode apiCode, String issue, Object data) {
return result((IApiCode)apiCode, (String)null, issue, data);
}
public static Result result(IApiCode apiCode, String msg, String issue, Object data) {
String message = apiCode.getMsg();
if (StringUtils.isNotBlank(msg)) {
message = msg;
}
return result(apiCode.getCode(), message, issue, data);
}
public static Result result(String code, String msg, String issue, Object data) {
return builder().code(code).success("0".equals(code)).msg(msg).issue(issue).data(data).build();
}
public static Result ok() {
return ok((Object)null);
}
public static Result ok(Object data) {
return result(ApiErrorCode.SUCCESS, data);
}
public static Result ok(String key, Object value) {
Map<String, Object> map = new HashMap(1);
map.put(key, value);
return ok(map);
}
public static Result fail(String msg) {
return result((IApiCode)ApiErrorCode.FAIL, msg, msg, (Object)null);
}
public static Result fail(IApiCode apiCode) {
return result(apiCode, (Object)null);
}
public static Result fail(IApiCode apiCode, String issue) {
return result(apiCode, issue, (Object)null);
}
public static Result fail(String code, String msg) {
return result((String)code, msg, msg, (Object)null);
}
public static Result fail(String code, String msg, String issue) {
return result((String)code, msg, issue, (Object)null);
}
public static Result fail(String code, String msg, String issue, Object data) {
return result(code, msg, issue, data);
}
public static Result fail(IApiCode apiCode, String issue, Object data) {
if (ApiErrorCode.SUCCESS == apiCode) {
throw new RuntimeException("失败结果状态码不能为" + ApiErrorCode.SUCCESS.getCode());
} else {
return result(apiCode, issue, data);
}
}
public static Result fail(String key, Object value) {
Map<String, Object> map = new HashMap();
map.put(key, value);
return result(ApiErrorCode.FAIL, map);
}
public Result() {
}
}

View File

@ -0,0 +1,55 @@
package com.sczx.car.common.enums;
import com.sczx.car.common.IApiCode;
/**
* @Author: 张黎
* @Date: 2025/07/09/20:22
* @Description:
*/
public enum ApiErrorCode implements IApiCode {
SUCCESS("0", "操作成功"),
ARG_ERROR("401000", "参数错误"),
NOT_PERMISSION("401001", "没有权限"),
HTTP_MEDIA_TYPE_NOT_SUPPORTED_ERROR("401002", "media类型出错"),
HTTP_METHOD_NOT_ALLOW_ERROR("401003", "http请求method错误"),
BODY_NOT_MATCH("401004", "请求的数据格式不符!"),
NOT_FOUND("404000", "你请求的路径不存在"),
UNAUTHORIZED("404001", "非法访问"),
FAIL("500000", "操作失败"),
INNER_ERROR("500001", "服务器内部异常");
private final String code;
private final String msg;
private ApiErrorCode(String code, String msg) {
this.code = code;
this.msg = msg;
}
public static ApiErrorCode getApiCode(String code) {
ApiErrorCode[] ecs = values();
ApiErrorCode[] var2 = ecs;
int var3 = ecs.length;
for(int var4 = 0; var4 < var3; ++var4) {
ApiErrorCode ec = var2[var4];
if (ec.getCode().equals(code)) {
return ec;
}
}
return SUCCESS;
}
@Override
public String getCode() {
return this.code;
}
@Override
public String getMsg() {
return this.msg;
}
}

View File

@ -0,0 +1,18 @@
package com.sczx.car.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;
}
}

View File

@ -0,0 +1,47 @@
package com.sczx.car.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Arrays;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.sczx.store.controller")) // 修改为你的 controller 包路径
.paths(PathSelectors.any())
.build()
.globalOperationParameters(Arrays.asList(
new ParameterBuilder()
.name("Authorization")
.description("Bearer Token")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(true)
.build()
));
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("门店服务接口文档")
.description("sczx_store门店服务接口文档文档")
.version("1.0")
.build();
}
}

View File

@ -0,0 +1,23 @@
package com.sczx.car.constant;
/**
* 应用模块名称<p>
* <p>
* 代码描述<p>
* <p>
* Copyright: Copyright (C) 2022 CD Finance Management Co., Ltd. All rights reserved. <p>
* <p>
* Company: 中和农信项目管理有限公司<p>
*
* @author zhonghui
* @since 2022/4/1 3:33 PM
*/
public interface SystemConstants {
/***
* feign客户端所在包路径
*/
String FEIGN_CLIENT_BASE_PACKAGE = "com.sczx.app.thirdpart.facade";
}

View File

@ -0,0 +1,85 @@
package com.sczx.car.exception;
import com.sczx.car.common.IApiCode;
import com.sczx.car.common.enums.ApiErrorCode;
/**
*
* @author zhangli
*/
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
protected String errorCode;
/**
* 错误信息
*/
protected String errorMsg;
public BizException() {
super();
}
public BizException(IApiCode apiCode) {
super(apiCode.getCode());
this.errorCode = apiCode.getCode();
this.errorMsg = apiCode.getMsg();
}
public BizException(IApiCode apiCode, Throwable cause) {
super(apiCode.getCode(), cause);
this.errorCode = apiCode.getCode();
this.errorMsg = apiCode.getMsg();
}
public BizException(String errorMsg) {
super(errorMsg);
this.errorCode = ApiErrorCode.FAIL.getCode();
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg) {
super(errorCode);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg, Throwable cause) {
super(errorCode, cause);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
@Override
public String getMessage() {
return errorMsg;
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}

View File

@ -0,0 +1,49 @@
package com.sczx.car.exception;
import com.sczx.car.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
/**
* @author zhangli
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理自定义的业务异常
*
* @param req
* @param e
* @return
*/
@ExceptionHandler(value = BizException.class)
@ResponseBody
public Result bizExceptionHandler(HttpServletRequest req, BizException e) {
log.warn("发生业务异常!原因是:{}", e.getErrorMsg(), e);
return Result.fail(e.getErrorCode(), e.getErrorMsg());
}
@ExceptionHandler(value = InnerException.class)
@ResponseBody
public Result innerExceptionHandler(HttpServletRequest req, InnerException e) {
log.error("发生服务内部异常!原因是:{}", e.getErrorMsg(), e);
return Result.fail(e.getErrorCode(), e.getErrorMsg());
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result exceptionHandler(HttpServletRequest req, Exception e) {
log.error("意料外异常!原因是:{}", e.getMessage(), e);
return Result.fail("99999", "系统内部异常");
}
}

View File

@ -0,0 +1,86 @@
package com.sczx.car.exception;
import com.sczx.car.common.IApiCode;
import com.sczx.car.common.enums.ApiErrorCode;
/**
*
* @author zhangli
*/
public class InnerException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
protected String errorCode;
/**
* 错误信息
*/
protected String errorMsg;
public InnerException() {
super();
}
public InnerException(IApiCode apiCode) {
super(apiCode.getCode());
this.errorCode = apiCode.getCode();
this.errorMsg = apiCode.getMsg();
}
public InnerException(IApiCode apiCode, Throwable cause) {
super(apiCode.getCode(), cause);
this.errorCode = apiCode.getCode();
this.errorMsg = apiCode.getMsg();
}
public InnerException(String errorMsg) {
super(errorMsg);
this.errorCode = ApiErrorCode.INNER_ERROR.getCode();
this.errorMsg = errorMsg;
}
public InnerException(String errorCode, String errorMsg) {
super(errorCode);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public InnerException(String errorCode, String errorMsg, Throwable cause) {
super(errorCode, cause);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
@Override
public String getMessage() {
return errorMsg;
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}

View File

@ -0,0 +1,159 @@
package com.sczx.car.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<String> getMacAddressList() throws IOException {
final ArrayList<String> macAddressList = new ArrayList<String>();
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<String> macList = getMacAddressList();
for (Iterator<String> 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());
}
}

View File

@ -0,0 +1,63 @@
package com.sczx.car.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;
}
}
}

View File

@ -0,0 +1,33 @@
package com.sczx.car.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
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);
}
}