Commit 517de7c9 by kenzo

update object

parent 579e3f29
<?xml version="1.0" encoding="UTF-8"?> <?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" <project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.cnooc</groupId>
<artifactId>expert-manage-miniapp</artifactId>
<version>1.0.0</version>
<name>Expert Manage MiniApp</name>
<description>Expert Management Mini Application</description>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version> <version>2.7.18</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>com.cnooc</groupId>
<artifactId>expert-manage-miniapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>expert-manage-miniapp</name>
<description>expert-manage-miniapp</description>
<url/>
<licenses>
<license/>
</licenses>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties> <properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>com.squareup.retrofit2</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>retrofit</artifactId>
<scope>test</scope> <version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.21</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mybatis.spring.boot</groupId> <groupId>com.squareup.retrofit2</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId> <artifactId>converter-gson</artifactId>
<version>2.1.4</version> <version>2.9.0</version>
</dependency> </dependency>
<!-- 工具类 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.12.0</version> <version>3.18.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>org.apache.commons</groupId>
<artifactId>fastjson</artifactId> <artifactId>commons-collections4</artifactId>
<version>2.0.7</version> <version>4.4</version>
</dependency>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>com.google.guava</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>guava</artifactId>
<version>3.12.0</version> <version>32.0.1-android</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration> <configuration>
<excludes> <source>1.8</source>
<exclude> <target>1.8</target>
<groupId>org.projectlombok</groupId> <encoding>UTF-8</encoding>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project>
</project> \ No newline at end of file
package com.cnooc.expert;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ExpertManageMiniApplication {
public static void main(String[] args) {
SpringApplication.run(ExpertManageMiniApplication.class, args);
}
}
package com.cnooc.expert;
import com.cnooc.expert.common.response.ApiResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Ping {
@GetMapping("/ping")
public ApiResult<String> ping() {
return ApiResult.successWithData("Pong");
}
}
package com.cnooc.expert.common.exception;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@Getter
@Slf4j
public class BusinessException extends RuntimeException {
private final ErrorCode errorCode;
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMsg());
this.errorCode = errorCode;
}
public BusinessException(ErrorCode errorCode, String message) {
super(StringUtils.defaultIfBlank(message, errorCode.getMsg()));
this.errorCode = errorCode;
}
}
package com.cnooc.expertmanageminiapp.common.exception.enums; package com.cnooc.expert.common.exception;
import lombok.Data; import lombok.Data;
/**
* 错误码对象
* @author: FuHongZhang
*/
@Data @Data
public class ErrorCode { public class ErrorCode {
/** /**
* 错误码 * 错误码
*/ */
private final Integer code; private final String code;
/** /**
* 错误提示 * 错误提示
*/ */
private final String msg; private final String msg;
public ErrorCode(Integer code, String msg) { public ErrorCode(String code, String msg) {
this.code = code; this.code = code;
this.msg = msg; this.msg = msg;
} }
......
package com.cnooc.expert.common.exception;
public interface GlobalErrorCodeConstants {
ErrorCode SUCCESS = new ErrorCode("200", "成功");
// ========== 系统级别错误 (1000-1999) ==========
ErrorCode BAD_REQUEST = new ErrorCode("1001", "请求参数不正确");
ErrorCode UNAUTHORIZED = new ErrorCode("1002", "账号未登录");
ErrorCode FORBIDDEN = new ErrorCode("1003", "没有该操作权限");
ErrorCode NOT_FOUND = new ErrorCode("1004", "请求未找到");
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode("1005", "请求方法不正确");
ErrorCode LOCKED = new ErrorCode("1006", "请求失败,请稍后重试");
ErrorCode TOO_MANY_REQUESTS = new ErrorCode("1007", "请求过于频繁,请稍后重试");
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode("1008", "系统异常");
ErrorCode NOT_IMPLEMENTED = new ErrorCode("1009", "功能未实现/未开启");
ErrorCode ERROR_CONFIGURATION = new ErrorCode("1010", "错误的配置项");
ErrorCode CAPTCHA_EXPIRED = new ErrorCode("1011", "验证码错误");
ErrorCode CODE_REDIS_KEY = new ErrorCode("1011", "验证码已过期");
ErrorCode SYSTEM_ERROR = new ErrorCode("1012", "系统内部异常");
// ========== 用户认证相关错误 (2000-2999) ==========
ErrorCode LOGIN_EXPIRED = new ErrorCode("2001", "请先登录");
ErrorCode USER_NOT_EXISTS = new ErrorCode("2002", "用户不存在");
ErrorCode PASSWORD_ERROR = new ErrorCode("2003", "密码错误");
ErrorCode USER_DISABLED = new ErrorCode("2004", "用户已被禁用");
// ========== 参数校验错误 (3000-3999) ==========
ErrorCode PARAM_REQUIRED = new ErrorCode("3001", "必填字段不能为空");
ErrorCode PARAM_FORMAT_ERROR = new ErrorCode("3002", "参数格式不正确");
ErrorCode PARAM_RANGE_ERROR = new ErrorCode("3003", "参数超出范围");
// ========== 业务逻辑错误 (4000-4999) ==========
ErrorCode OPERATION_TOO_FREQUENT = new ErrorCode("4001", "操作太频繁,请稍后再试");
ErrorCode DATA_ALREADY_EXISTS = new ErrorCode("4002", "数据已存在");
ErrorCode DATA_NOT_EXISTS = new ErrorCode("4003", "数据不存在");
ErrorCode BUSINESS_FAILED = new ErrorCode("4004", "业务处理失败");
// ========== 数据访问错误 (5000-5999) ==========
ErrorCode DATABASE_CONNECTION_ERROR = new ErrorCode("5001", "数据库连接失败");
ErrorCode QUERY_DATA_ERROR = new ErrorCode("5002", "查询数据出错");
ErrorCode INSERT_DATA_ERROR = new ErrorCode("5003", "插入数据出错");
ErrorCode UPDATE_DATA_ERROR = new ErrorCode("5004", "更新数据出错");
ErrorCode DELETE_DATA_ERROR = new ErrorCode("5005", "删除数据出错");
}
package com.cnooc.expertmanageminiapp.common.exception; package com.cnooc.expert.common.exception;
import com.cnooc.expertmanageminiapp.common.exception.enums.GlobalErrorCodeConstants; import com.cnooc.expert.common.response.ApiResult;
import com.cnooc.expertmanageminiapp.common.response.Result;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
/**
* 全局异常处理类
* @author: FuHongZhang
*/
@RestControllerAdvice
@Slf4j @Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
/** /**
* 处理参数校验异常 * 处理参数校验异常
*/ */
@ExceptionHandler(MethodArgumentNotValidException.class) @ExceptionHandler(MethodArgumentNotValidException.class)
public Result<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, public ApiResult<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e,
HttpServletRequest request) { HttpServletRequest request) {
log.error("参数校验失败: {},请求URL: {}", e.getMessage(), request.getRequestURI()); log.error("参数校验失败: {},请求URL: {}", e.getMessage(), request.getRequestURI());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
e.getBindingResult().getFieldErrors().forEach(error -> e.getBindingResult().getFieldErrors().forEach(error ->
sb.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; ") sb.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; ")
); );
return Result.error("参数校验失败" + sb); return ApiResult.error("参数校验失败" + sb);
} }
/** /**
* 处理绑定异常 * 处理绑定异常
*/ */
@ExceptionHandler(BindException.class) @ExceptionHandler(BindException.class)
public Result<String> handleBindException(BindException e, HttpServletRequest request) { public ApiResult<String> handleBindException(BindException e, HttpServletRequest request) {
log.error("参数绑定失败: {},请求URL: {}", e.getMessage(), request.getRequestURI()); log.error("参数绑定失败: {},请求URL: {}", e.getMessage(), request.getRequestURI());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
e.getBindingResult().getFieldErrors().forEach(error -> e.getBindingResult().getFieldErrors().forEach(error ->
sb.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; ") sb.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; ")
); );
return Result.error("参数绑定失败" + sb); return ApiResult.error("参数绑定失败" + sb);
} }
/** /**
* 处理参数验证异常
*/
@ExceptionHandler(ConstraintViolationException.class)
public Result<String> handleConstraintViolationException(ConstraintViolationException e,
HttpServletRequest request) {
log.error("参数验证失败: {},请求URL: {}", e.getMessage(), request.getRequestURI());
StringBuilder sb = new StringBuilder();
e.getConstraintViolations().forEach(violation ->
sb.append(violation.getPropertyPath()).append(": ").append(violation.getMessage()).append("; ")
);
// 移除末尾的分号和空格
String errorMsg = sb.length() > 0 ? sb.substring(0, sb.length() - 2) : "参数验证失败";
return Result.error(errorMsg);
}
/**
* 处理其他异常 * 处理其他异常
*/ */
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public Result<String> handleException(Exception e, HttpServletRequest request) { public ApiResult<String> handleException(Exception e, HttpServletRequest request) {
log.error("系统异常: {},请求URL: {}", e.getMessage(), request.getRequestURI(), e); log.error("系统异常: {},请求URL: {}", e.getMessage(), request.getRequestURI(), e);
return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), GlobalErrorCodeConstants.SYSTEM_ERROR.getMsg()); return ApiResult.error(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), GlobalErrorCodeConstants.SYSTEM_ERROR.getMsg());
} }
@ExceptionHandler(BusinessException.class) @ExceptionHandler(BusinessException.class)
public Result<String> handleBusinessException(BusinessException e, HttpServletRequest request) { public ApiResult<String> handleBusinessException(BusinessException e, HttpServletRequest request) {
log.error("业务异常: {},请求URL: {}", e.getMessage(), request.getRequestURI(), e); log.error("业务异常: {},请求URL: {}", e.getMessage(), request.getRequestURI(), e);
return Result.error(e.getErrorCode(), e.getMessage()); return ApiResult.error(e.getMessage(), e.getMessage());
} }
@ExceptionHandler(NullPointerException.class) @ExceptionHandler(NullPointerException.class)
public Result<String> handleNullPointerException(NullPointerException e, HttpServletRequest request) { public ApiResult<String> handleNullPointerException(NullPointerException e, HttpServletRequest request) {
log.error("空指针异常: {},请求URL: {}", e.getMessage(), request.getRequestURI(), e); log.error("空指针异常: {},请求URL: {}", e.getMessage(), request.getRequestURI(), e);
return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), GlobalErrorCodeConstants.SYSTEM_ERROR.getMsg()); return ApiResult.error(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), GlobalErrorCodeConstants.SYSTEM_ERROR.getMsg());
} }
} }
package com.cnooc.expert.common.filter;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.annotation.Priority;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Map;
@Component
@Priority(Integer.MAX_VALUE - 2)
public class LoggingFilter extends OncePerRequestFilter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getRequestURI().startsWith("/actuator")
|| "/health".equals(request.getRequestURI())
|| request.getRequestURI().endsWith(".php")
) {
filterChain.doFilter(request, response);
return;
}
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
Instant start = Instant.now();
filterChain.doFilter(requestWrapper, responseWrapper);
Instant end = Instant.now();
String requestBody = readRequest(requestWrapper);
String responseBody;
if (!Strings.isNullOrEmpty(responseWrapper.getContentType()) &&
responseWrapper.getContentType().contains("stream")) { // 下载类的返回不打印到控制台.
responseBody = "<<binary>>";
} else if (request.getRequestURI().contains("/basic/geo-list")) {
responseBody = "<<Full Geo List>>";
} else if (request.getRequestURI().contains("/basic/qrcode")) {
responseBody = "<<qrcode image>>";
} else if (request.getRequestURI().contains("/institution/get-institution-detail")) {
responseBody = "<<institution detail>>";
} else {
responseBody = new String(responseWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
}
responseWrapper.copyBodyToResponse();
logger.info("{} {} {}\n<<<<<<<<<<\nq= {}\nt= {} ms\nr= {}\n>>>>>>>>>>\n",
request.getMethod(),
request.getRequestURI(),
responseWrapper.getStatus(),
requestBody,
Duration.between(start, end).toMillis(),
responseBody);
}
private String readRequest(ContentCachingRequestWrapper request) {
if ("GET".equals(request.getMethod())) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String[]> e : request.getParameterMap().entrySet()) {
sb.append(e.getKey()).append(":").append(Arrays.toString(e.getValue())).append(", ");
}
return sb.toString();
} else if ("POST".equals(request.getMethod())) {
return new String(request.getContentAsByteArray(), StandardCharsets.UTF_8);
} else {
return request.getMethod();
}
}
}
package com.cnooc.expertmanageminiapp.common.response; package com.cnooc.expert.common.response;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.io.Serializable; import java.io.Serializable;
/**
* 通用响应结果类
* @author: FuHongZhang
*/
@Setter @Setter
@Getter @Getter
public class Result<T> implements Serializable { public class ApiResult<T> implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 响应码 * 响应码
*/ */
private Integer code; private String code;
/** /**
* 响应消息 * 响应消息
*/ */
private String message; private String message;
/** /**
* 响应数据 * 响应数据
*/ */
private T data; private T data;
/**
* 是否成功
*/
private Boolean success;
public Result(Integer code, String message, T data, Boolean success) { public ApiResult(String code, String message, T data) {
this.code = code; this.code = code;
this.message = message; this.message = message;
this.data = data; this.data = data;
this.success = success;
} }
/** /**
* 成功返回结果 * 成功返回结果
*/ */
public static <T> Result<T> success(T data) { public static <T> ApiResult<T> successWithData(T data) {
return new Result<>(200, "操作成功", data, true); return new ApiResult<>("200", "操作成功", data);
} }
/** /**
* 成功返回结果 * 成功返回结果
*/ */
public static <T> Result<T> success() { public static <T> ApiResult<T> success() {
return new Result<>(200, "操作成功", null, true); return new ApiResult<>("200", "操作成功", null);
} }
public static <T> Result<T> success(String message) { public static <T> ApiResult<T> success(String message) {
return new Result<>(200, message, null, true); return new ApiResult<>("200", message, null);
} }
/** /**
* 失败返回结果 * 失败返回结果
*/ */
public static <T> Result<T> error(String message) { public static <T> ApiResult<T> error(String message) {
return new Result<>(500, message, null, false); return new ApiResult<>("500", message, null);
} }
/** /**
* 失败返回结果 * 失败返回结果
*/ */
public static <T> Result<T> error(Integer code, String message) { public static <T> ApiResult<T> error(String code, String message) {
return new Result<>(code, message, null, false); return new ApiResult<>(code, message, null);
} }
// Getters and Setters // Getters and Setters
} }
package com.cnooc.expert.config;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class GsonConfig {
@Bean
@Primary
public Gson gson() {
return new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.setPrettyPrinting()
.serializeNulls() // 序列化null值
.create();
}
}
package com.cnooc.expert.config;
import com.google.gson.Gson;
import okhttp3.OkHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import java.util.concurrent.TimeUnit;
@Configuration
public class RetrofitConfiguration {
@Bean("retrofitExpert")
@Primary
public Retrofit RetrofitExpert(Gson gson) {
return createRetrofit("https://randomuser.me/", gson);
}
@Bean("retrofitWorkflow")
public Retrofit RetrofitWorkflow(Gson gson) {
return createRetrofit("https://randomuser.com/api/", gson);
}
private Retrofit createRetrofit(String baseUrl, Gson gson) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
}
package com.cnooc.expert.controller.person;
import com.cnooc.expert.common.response.ApiResult;
import com.cnooc.expert.controller.person.model.request.PersonGetReq;
import com.cnooc.expert.service.PersonService;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@AllArgsConstructor
@RestController
@RequestMapping("/person")
public class PersonController {
private final PersonService personService;
@GetMapping("/get")
// public ApiResult<String> personGet(@RequestBody @Validated PersonGetReq req) {
public ApiResult<String> personGet() {
return ApiResult.successWithData(personService.getExpertDetail(1));
}
}
package com.cnooc.expert.controller.person.model.request;
import lombok.Data;
@Data
public class PersonGetReq {
private Long id;
}
package com.cnooc.expert.external.common;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import retrofit2.Call;
import retrofit2.Response;
import java.io.IOException;
@Slf4j
public abstract class AbstractRetrofitManager {
protected final ObjectMapper objectMapper;
public AbstractRetrofitManager() {
objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
// 结果检查
protected <T> T getResponseBody(Call<T> call, String func) {
log.info("{}", call.request());
try {
Response<T> response = call.execute();
if (response.isSuccessful()) {
log.debug("{}, code={}, message={}", func, response.code(), response.message());
T body = response.body();
log.info("{}", body);
return body;
} else {
log.warn("{} not successful, code={}, message={}", func, response.code(), response.message());
return null;
}
} catch (IOException e) {
e.printStackTrace();
log.warn("{}, IOException, message={}", func, e.getMessage());
return null;
}
}
}
package com.cnooc.expert.external.expert.api;
import com.cnooc.expert.external.expert.model.request.ExpertInfoGetReq;
import com.cnooc.expert.external.expert.model.response.ExpertInfoGetResp;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.HeaderMap;
import retrofit2.http.POST;
import java.util.Map;
public interface ExpertServiceApi {
// GET请求
@GET("/api")
Call<ExpertInfoGetResp> expertDetailGet(@HeaderMap Map<String, Object> headers);
@POST("/")
Call<ExpertInfoGetResp> expertDetailUpDate(@HeaderMap Map<String, Object> headers, @Body ExpertInfoGetReq user);
}
package com.cnooc.expert.external.expert.model.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ExpertInfoGetReq {
private Long userId;
}
package com.cnooc.expert.external.expert.model.response;
import lombok.Data;
@Data
public class ExpertInfoGetInfo {
private String seed;
private Integer results;
private Integer page;
private String version;
}
package com.cnooc.expert.external.expert.model.response;
import lombok.Data;
import java.util.List;
@Data
public class ExpertInfoGetResp {
private List<ExpertInfoGetResult> results;
private ExpertInfoGetInfo info;
}
package com.cnooc.expert.external.expert.model.response;
import lombok.Data;
@Data
public class ExpertInfoGetResult {
private String gender;
private String email;
}
package com.cnooc.expert.external.expert.service;
import com.cnooc.expert.external.common.AbstractRetrofitManager;
import com.cnooc.expert.external.expert.api.ExpertServiceApi;
import com.cnooc.expert.external.expert.model.response.ExpertInfoGetResp;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import retrofit2.Call;
import retrofit2.Retrofit;
import java.util.Map;
@Service
public class ExpertService extends AbstractRetrofitManager {
private final ExpertServiceApi expertServiceApi;
public ExpertService(@Qualifier("retrofitExpert") Retrofit retrofit) {
this.expertServiceApi = retrofit.create(ExpertServiceApi.class);
}
public ExpertInfoGetResp getExpertInfo(long id) {
Map<String, Object> headers = Maps.newHashMap();
Call<ExpertInfoGetResp> call = expertServiceApi.expertDetailGet(headers);
return this.getResponseBody(call, "getExpertInfo");
}
}
package com.cnooc.expert.service;
import com.cnooc.expert.controller.person.model.request.PersonGetReq;
import com.cnooc.expert.external.expert.model.response.ExpertInfoGetResp;
import com.cnooc.expert.external.expert.service.ExpertService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@AllArgsConstructor
@Service
public class PersonService {
private final ExpertService expertService;
public String getExpertDetail(int id) {
ExpertInfoGetResp expertInfo = expertService.getExpertInfo(id);
return StringUtils.defaultIfBlank(expertInfo.getInfo().getSeed(), "") ;
}
}
package com.cnooc.expertmanageminiapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* 小程序启动类
*/
@SpringBootApplication(scanBasePackages = "com.cnooc.expertmanageminiapp")
public class ExpertManageMiniappApplication {
public static void main(String[] args) {
SpringApplication.run(ExpertManageMiniappApplication.class, args);
}
}
package com.cnooc.expertmanageminiapp.common.config;
import com.cnooc.expertmanageminiapp.common.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author: FuHongZhang
* @date 2025-10-16 11:05
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册登录拦截器,并设置拦截路径和排除路径
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**") // 拦截所有路径
.excludePathPatterns( // 排除一些路径
"/sys/**",
"/verify/**",
"/person/**",
"/text/**"
);
}
}
package com.cnooc.expertmanageminiapp.common.constant;
/**
* Token的Key常量
*
* @author FuHongZhang
*/
public class TokenConstants
{
/**
* 令牌前缀
* todo 暂时不用
*/
public static final String PREFIX = "Bearer ";
/**
* 令牌秘钥
*/
public final static String SECRET = "DjLRzlhhd/gdx6kPXtfBUSMiL8d0VzDYAtWBKpt3BuA=";
/**
* uuid_key 用于拼接缓存token的key
*/
public static final String UUID_KEY = "uuid_key";
/**
* 用户id
*/
public static final String USER_ID = "user_id";
/**
* 用于拼接缓存token的key
*/
public static final String TOKEN_KEY_ = "TOKEN:TOKEN_KEY_";
}
package com.cnooc.expertmanageminiapp.common.exception;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
/**
* 通用业务自定义异常
* 适用于参数校验、业务规则冲突、权限校验等所有业务层面的异常场景
*/
@Getter
@Slf4j
public class BusinessException extends RuntimeException {
// ------------------- Getter 方法(仅提供获取,不允许修改) -------------------
/**
* 错误码(标准化,如:40001=参数错误,40301=权限不足,50001=系统异常)
* 建议遵循 HTTP 状态码规范,扩展业务子码(如 400 开头为客户端错误,500 开头为服务端错误)
*/
private final Integer errorCode;
/**
* 业务场景标识(如:"user_register"=用户注册,"order_pay"=订单支付,便于定位异常来源)
*/
private final String businessScene;
/**
* 异常关联数据(可选,存储导致异常的关键业务数据,如:{"userId":"10086","phone":"13800138000"})
*/
private final Map<String, Object> errorData;
// ------------------- 构造方法(按场景重载) -------------------
/**
* 基础构造器:仅包含错误信息(适用于简单场景)
* @param message 异常描述信息
*/
public BusinessException(String message) {
super(message);
this.errorCode = 500; // 默认错误码
this.businessScene = "系统错误"; // 默认未知场景
this.errorData = null;
// 记录日志
log.error("BusinessException occurred: {}", message);
}
/**
* 构造器:带错误码+错误信息(最常用,标准化异常响应)
* @param errorCode 错误码(如:"40001")
* @param message 异常描述信息
*/
public BusinessException(Integer errorCode, String message) {
super(message);
this.errorCode = errorCode;
this.businessScene = "UNKNOWN";
this.errorData = null;
// 记录日志
log.error("BusinessException occurred - Code: {}, Message: {}", errorCode, message);
}
/**
* 构造器:带错误码+错误信息+业务场景(精准定位异常来源)
* @param errorCode 错误码
* @param message 异常描述信息
* @param businessScene 业务场景(如:"user_login")
*/
public BusinessException(Integer errorCode, String message, String businessScene) {
super(message);
this.errorCode = errorCode;
this.businessScene = businessScene;
this.errorData = null;
// 记录日志
log.error("BusinessException occurred - Code: {}, Scene: {}, Message: {}",
errorCode, businessScene, message);
}
/**
* 构造器:带完整信息(错误码+信息+场景+异常数据,便于排查)
* @param errorCode 错误码
* @param message 异常描述信息
* @param businessScene 业务场景
* @param errorData 异常关联数据(如错误的参数、用户ID等)
*/
public BusinessException(Integer errorCode, String message, String businessScene, Map<String, Object> errorData) {
super(message);
this.errorCode = errorCode;
this.businessScene = businessScene;
this.errorData = errorData;
// 记录日志
log.error("BusinessException occurred - Code: {}, Scene: {}, Message: {}, Data: {}",
errorCode, businessScene, message, errorData);
}
/**
* 构造器:带根因异常(用于包装底层异常,如SQL异常、IO异常)
* @param errorCode 错误码
* @param message 异常描述信息
* @param cause 根因异常(底层原始异常)
*/
public BusinessException(Integer errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
this.businessScene = "UNKNOWN";
this.errorData = null;
// 记录日志
log.error("BusinessException occurred - Code: {}, Message: {}, Cause: {}",
errorCode, message, cause.getClass().getSimpleName());
}
/**
* 构造器:全参数(适配复杂场景)
* @param errorCode 错误码
* @param message 异常描述信息
* @param businessScene 业务场景
* @param errorData 异常关联数据
* @param cause 根因异常
*/
public BusinessException(Integer errorCode, String message, String businessScene, Map<String, Object> errorData, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
this.businessScene = businessScene;
this.errorData = errorData;
// 记录日志
log.error("BusinessException occurred - Code: {}, Scene: {}, Message: {}, Data: {}, Cause: {}",
errorCode, businessScene, message, errorData, cause.getClass().getSimpleName());
}
// ------------------- 增强异常信息可读性 -------------------
@Override
public String toString() {
StringBuilder sb = new StringBuilder("BusinessException: [");
sb.append("errorCode=").append(errorCode)
.append(", businessScene=").append(businessScene)
.append(", message=").append(getMessage()).append("]");
// 追加异常数据(若存在)
if (errorData != null && !errorData.isEmpty()) {
sb.append(" | errorData=").append(errorData);
}
// 追加根因异常(若存在)
if (getCause() != null) {
sb.append(" | cause=").append(getCause().getClass().getSimpleName());
}
return sb.toString();
}
}
\ No newline at end of file
package com.cnooc.expertmanageminiapp.common.exception.enums;
/**
* 全局错误码枚举
*
*
* @author FuHongZhang
*/
public interface GlobalErrorCodeConstants {
ErrorCode SUCCESS = new ErrorCode(0, "成功");
// ========== 系统级别错误 (1000-1999) ==========
ErrorCode BAD_REQUEST = new ErrorCode(1001, "请求参数不正确");
ErrorCode UNAUTHORIZED = new ErrorCode(1002, "账号未登录");
ErrorCode FORBIDDEN = new ErrorCode(1003, "没有该操作权限");
ErrorCode NOT_FOUND = new ErrorCode(1004, "请求未找到");
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(1005, "请求方法不正确");
ErrorCode LOCKED = new ErrorCode(1006, "请求失败,请稍后重试");
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(1007, "请求过于频繁,请稍后重试");
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(1008, "系统异常");
ErrorCode NOT_IMPLEMENTED = new ErrorCode(1009, "功能未实现/未开启");
ErrorCode ERROR_CONFIGURATION = new ErrorCode(1010, "错误的配置项");
ErrorCode CAPTCHA_EXPIRED = new ErrorCode(1011, "验证码错误");
ErrorCode CODE_REDIS_KEY = new ErrorCode(1011, "验证码已过期");
ErrorCode SYSTEM_ERROR = new ErrorCode(1012, "系统内部异常");
// ========== 用户认证相关错误 (2000-2999) ==========
ErrorCode LOGIN_EXPIRED = new ErrorCode(2001, "请先登录");
ErrorCode USER_NOT_EXISTS = new ErrorCode(2002, "用户不存在");
ErrorCode PASSWORD_ERROR = new ErrorCode(2003, "密码错误");
ErrorCode USER_DISABLED = new ErrorCode(2004, "用户已被禁用");
// ========== 参数校验错误 (3000-3999) ==========
ErrorCode PARAM_REQUIRED = new ErrorCode(3001, "必填字段不能为空");
ErrorCode PARAM_FORMAT_ERROR = new ErrorCode(3002, "参数格式不正确");
ErrorCode PARAM_RANGE_ERROR = new ErrorCode(3003, "参数超出范围");
// ========== 业务逻辑错误 (4000-4999) ==========
ErrorCode OPERATION_TOO_FREQUENT = new ErrorCode(4001, "操作太频繁,请稍后再试");
ErrorCode DATA_ALREADY_EXISTS = new ErrorCode(4002, "数据已存在");
ErrorCode DATA_NOT_EXISTS = new ErrorCode(4003, "数据不存在");
ErrorCode BUSINESS_FAILED = new ErrorCode(4004, "业务处理失败");
// ========== 数据访问错误 (5000-5999) ==========
ErrorCode DATABASE_CONNECTION_ERROR = new ErrorCode(5001, "数据库连接失败");
ErrorCode QUERY_DATA_ERROR = new ErrorCode(5002, "查询数据出错");
ErrorCode INSERT_DATA_ERROR = new ErrorCode(5003, "插入数据出错");
ErrorCode UPDATE_DATA_ERROR = new ErrorCode(5004, "更新数据出错");
ErrorCode DELETE_DATA_ERROR = new ErrorCode(5005, "删除数据出错");
}
package com.cnooc.expertmanageminiapp.common.interceptor;
import com.cnooc.expertmanageminiapp.common.constant.TokenConstants;
import com.cnooc.expertmanageminiapp.common.exception.BusinessException;
import com.cnooc.expertmanageminiapp.common.exception.enums.GlobalErrorCodeConstants;
import com.cnooc.expertmanageminiapp.common.utils.JwtUtils;
import com.cnooc.expertmanageminiapp.common.utils.UserUtils;
import com.cnooc.expertmanageminiapp.common.utils.ValidUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;
/**
* @author: FuHongZhang
* @date 2025-10-16 10:22
*/
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || token.trim().isEmpty()) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
throw new BusinessException(HttpServletResponse.SC_UNAUTHORIZED, GlobalErrorCodeConstants.LOGIN_EXPIRED.getMsg());
}
try {
Map<String, String> userMap = JwtUtils.getTokenInfo(token);
int userId = Integer.parseInt(userMap.get(TokenConstants.USER_ID));
String uuidKey = userMap.get(TokenConstants.UUID_KEY);
ValidUtils.isNotNull(uuidKey, "登录异常,请重新登录");
String cachedToken = redisTemplate.opsForValue().get(TokenConstants.TOKEN_KEY_ + userId);
if (cachedToken == null || !cachedToken.equals(token)) {
// token不存在或不匹配,说明已退出登录或token失效
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"code\":401,\"msg\":\"请先登录\"}");
return false;
}
// 验证token是否过期
if (JwtUtils.isTokenExpired(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
// todo 通过token解析出用户id,代用UserUtils.setUserId(userId)方法进行存储
// 所有条件都满足,放行请求
return true;
} catch (Exception e) {
log.info("token解析异常 {}",e.getMessage(),e);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
UserUtils.clear();
throw new BusinessException(401, "请先登录");
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserUtils.clear();
}
}
/**
*
*/
package com.cnooc.expertmanageminiapp.common.utils;
import com.cnooc.expertmanageminiapp.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
/**
* @author lyh
* 2016年10月24日 上午9:34:32
*/
@Slf4j
public class AesUtil {
private static final String KEY_TYPE = "AES";
private static final String CIPHER_TYPE = "AES/ECB/PKCS5Padding";
/**
* 加密
*
* @param content
* 要加密的内容
* @param password
* 密码
* @return 加密后的字符串
*/
public static String encrypt(String content, String password) {
String realKey = AesUtil.md5Encode(password);
SecretKeySpec sks = new SecretKeySpec(AesUtil.hex2byte(realKey),
KEY_TYPE);
byte[] cipherByte = null;
try {
Cipher c1 = Cipher.getInstance(CIPHER_TYPE);
c1.init(Cipher.ENCRYPT_MODE, sks);
cipherByte = c1.doFinal(content.getBytes("UTF-8"));
// 返回密文的十六进制形式
return byte2hex(cipherByte);
} catch (Exception e) {
log.error("e:{}", e);
throw new BusinessException("加密失败");
}
}
/**
* 解密
*
* @param content
* 要解密的内容
* @param password
* 密码
* @return 解密结果
*/
public static String decrypt(String content, String password) {
String realKey = AesUtil.md5Encode(password);
SecretKeySpec sks = new SecretKeySpec(AesUtil.hex2byte(realKey),
KEY_TYPE);
byte[] cipherByte = null;
try {
Cipher c1 = Cipher.getInstance(CIPHER_TYPE);
c1.init(Cipher.DECRYPT_MODE, sks);
cipherByte = c1.doFinal(hex2byte(content));
return new String(cipherByte);
} catch (Exception e) {
log.error("e:{}", e);
throw new BusinessException("解密失败");
}
}
/**
* 生成MD5摘要
*/
public static String md5Encode(String info) {
try {
MessageDigest alga = MessageDigest.getInstance("MD5");
alga.update(info.getBytes("UTF-8"));
return byte2hex(alga.digest());
} catch (Exception e) {
return null;
}
}
/**
* 将二进制转化为16进制字符串
*/
public static String byte2hex(byte[] b) {
StringBuilder bder = new StringBuilder();
String stmp = null;
for (int n = 0; n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0XFF);
if (stmp.length() == 1) {
bder.append("0");
}
bder.append(stmp);
}
return bder.toString().toUpperCase();
}
/**
* 十六进制字符串转化为byte数组
*/
private static byte[] hex2byte(String hex) {
if (hex.length() % 2 != 0) {
throw new IllegalArgumentException("参数长度不合法");
}
byte[] result = new byte[hex.length() / 2];
for (int i = 0; i < result.length; i++) {
result[i] = uniteBytes(hex.charAt(i * 2), hex.charAt(i * 2 + 1));
}
return result;
}
/**
* 将两个ASCII字符合成一个字节; 如:"EF"--> 0xEF
*
* @param c1
* @param c2
* @return byte
*/
private static byte uniteBytes(char c1, char c2) {
byte _b0 = Byte.decode("0x" + c1);
_b0 = (byte) (_b0 << 4);
byte _b1 = Byte.decode("0x" + c2);
return (byte) (_b0 ^ _b1);
}
}
package com.cnooc.expertmanageminiapp.common.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
/**
* 公用的工具类
* @author zhengkai
*
* @date 2015年5月25日 上午11:34:35
*/
public class CommonUtil {
public static final Long SO_FAR_TINE = new Long(-1L);
/**
* 时间转换成字符串(采用 yyyy-MM-dd HH:mm:ss)
* @param longtime
* @return
* @author zhengkai
* @date 2015年5月9日 下午2:43:28F
*/
public static String longTimeToString(Long longtime){
if (SO_FAR_TINE.equals(longtime)) {
return "至今";
}
if(longtime!=null){
Date dt=(new Date(longtime));
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(dt);
}
return "";
}
public static String LongTimeToStringOnDay(Long longtime){
if (SO_FAR_TINE.equals(longtime)) {
return "至今";
}
if(longtime!=null){
Date dt=(new Date(longtime));
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(dt);
}
return "";
}
/**
* 时间转换成字符串
* @param longtime
* @param formatter
* @return
* @author zhengkai
* @date 2015年5月9日 下午2:43:28
*/
public static String LongTimeToString(Long longtime,String formatter){
if (SO_FAR_TINE.equals(longtime)) {
return "至今";
}
if(longtime!=null){
Date dt=(new Date(longtime));
SimpleDateFormat sdf=new SimpleDateFormat(formatter);
return sdf.format(dt);
}
return "";
}
/**
* 字符串值是否相同
* <p>
* 注意:只比较视觉值 即null = '' = ' '
* </p>
*
* @param str1
* @param str2
* @return
*/
public static boolean stringValSame(String str1, String str2){
str1 = Objects.toString(str1, "").trim();
str2 = Objects.toString(str2, "").trim();
return str1.equals(str2);
}
/**
* 二开 - Boolean类型转成字符串展示
*
* @param val
* @return true->是;false->否
*/
public static String convertBool2Str(Boolean val){
if (Objects.isNull(val)) {
return "";
}
return Boolean.TRUE.equals(val) ? "是" : "否";
}
}
package com.cnooc.expertmanageminiapp.common.utils;
import com.cnooc.expertmanageminiapp.common.constant.TokenConstants;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
/**
* JWT工具类,用于生成、解析和验证token
* @author FuHongZhang
*/
public class JwtUtils {
// 密钥,实际项目中应放在配置文件中
private static final String SECRET_KEY = TokenConstants.SECRET;
// Token过期时间,这里设置为24小时
private static final long EXPIRATION_TIME = 24 * 60 * 60 * 1000;
/**
* 生成token
* @return token字符串
*/
public static String createToken(Integer userId , String uuidKey) {
Map<String, Object> claims = new HashMap<>();
claims.put(TokenConstants.UUID_KEY,uuidKey);
claims.put(TokenConstants.USER_ID,userId);
// 生成token
return Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
/**
* 从token中获取用于拼接缓存的key uuid_key 和用户 user_id
*/
public static Map<String, String> getTokenInfo(String token) {
Claims claims = extractAllClaims(token);
Map<String, String> userInfo = new HashMap<>();
userInfo.put(TokenConstants.UUID_KEY, (String) claims.get(TokenConstants.UUID_KEY));
userInfo.put(TokenConstants.USER_ID, (String) claims.get(TokenConstants.USER_ID));
return userInfo;
}
/**
*
* @param token
* @return
*/
private static Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
/**
* 校验token是否过期
* @param token
* @return
*/
public static boolean isTokenExpired(String token) {
//1.解析token中的key进行拼接,完了查询缓存是否存在
return false;
}
}
package com.cnooc.expertmanageminiapp.common.utils;
import com.cnooc.expertmanageminiapp.system.entity.pojo.ZhuanJiaUser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* 用户id获取工具类
* @author: FuHongZhang
* @date 2025-10-24 11:14:07
*/
@Component("userUtils")
public class UserUtils {
public static ZhuanJiaUser getCurrentUser() {
ZhuanJiaUser zhuanJiaUser = USER_INFO.get();
if (zhuanJiaUser != null) {
return zhuanJiaUser;
}
return null;
}
private static final ThreadLocal<ZhuanJiaUser> USER_INFO = new ThreadLocal<>();
public static void setUserId(ZhuanJiaUser zhuanJiaUser) {
USER_INFO.set(zhuanJiaUser);
}
public static ZhuanJiaUser getUserId() {
return USER_INFO.get();
}
public static void clear() {
USER_INFO.remove();
}
}
\ No newline at end of file
package com.cnooc.expertmanageminiapp.common.utils;
import com.cnooc.expertmanageminiapp.common.exception.BusinessException;
import com.cnooc.expertmanageminiapp.common.exception.enums.ErrorCode;
import com.cnooc.expertmanageminiapp.common.exception.enums.GlobalErrorCodeConstants;
import java.util.Collection;
/**
* @Author: FuHongZhang
* @CreateTime: 2025-09-18 16:11
*/
public class ValidUtils {
/**
* 校验字符串是否为空
* @param text 待校验的字符串
* @param message 异常信息
*/
public static void isText(String text, String message) {
if (text == null || text.trim().isEmpty()) {
throw new BusinessException(GlobalErrorCodeConstants.PARAM_FORMAT_ERROR.getCode(),message);
}
}
/**
* 校验对象是否为null
* @param obj 待校验的对象
* @param message 异常信息
*/
public static void isNotNull(Object obj, String message) {
if (obj == null) {
throw new BusinessException(GlobalErrorCodeConstants.PARAM_FORMAT_ERROR.getCode(),message);
}
}
/**
* 自定义错误码及错误信息
* @param obj
* @param errorCode
*/
public static void isNotNull(Object obj, ErrorCode errorCode) {
if (obj == null) {
throw new BusinessException(errorCode.getCode(), errorCode.getMsg());
}
}
/**
* 校验集合是否为空
* @param collection 待校验的集合
* @param message 异常信息
*/
public static void isNullList(Collection<?> collection, String message) {
if (collection == null || collection.isEmpty()) {
throw new BusinessException(GlobalErrorCodeConstants.PARAM_FORMAT_ERROR.getCode(),message);
}
}
/**
* 校验表达式是否为true
* @param expression 待校验的布尔表达式
* @param message 异常信息
*/
public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new BusinessException(GlobalErrorCodeConstants.PARAM_FORMAT_ERROR.getCode(),message);
}
}
/**
* 校验表达式是否为true
* @param expression
* @param errorCode
*/
public static void isTrue(boolean expression, ErrorCode errorCode) {
if (!expression) {
throw new BusinessException(errorCode.getCode(), errorCode.getMsg());
}
}
/**
* 校验表达式是否为false
* @param expression 待校验的布尔表达式
* @param message 异常信息
*/
public static void isFalse(boolean expression, String message) {
if (expression) {
throw new BusinessException(GlobalErrorCodeConstants.PARAM_FORMAT_ERROR.getCode(),message);
}
}
}
package com.cnooc.expertmanageminiapp.manage.controller;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.manage.service.AssessBidService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 评标项目
* @author: FuHongZhang
* @date 2025-10-23 16:46
*/
@Slf4j
@RestController
@RequestMapping("/bid")
public class AssessBidController {
@Autowired
private AssessBidService assessBidService;
/**
* 查看评标项目列表
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("getBidList")
public Result<List<String>> getBidList() {
return null;
}
/**
* 查看评标项目详情
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getBidInfoById")
public Result<String> getBidInfoById() {
return null;
}
}
package com.cnooc.expertmanageminiapp.manage.controller;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.manage.entity.pojo.ZhuanJiaInfo;
import com.cnooc.expertmanageminiapp.manage.service.PersonInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 个人信息
* @author: FuHongZhang
* @date 2025-10-23 15:52
*/
@Slf4j
@RestController
@RequestMapping("/person")
public class PersonInfoController {
@Autowired
private PersonInfoService personInfoService;
/**
* 获取专家个人信息
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getExpertInfo")
public Result<ZhuanJiaInfo> getPersonInfo() {
return personInfoService.getExpertPersonInfo();
}
/**
* 获取专家词典信息
*/
@GetMapping("/getExpertSysDictByParent")
public Result<String> getExpertSysDictByParent() {
return null;
}
@GetMapping("/getDictsByParentGuid")
public Result<String> getDictsByParentGuid() {
return null;
}
/**
* 获取枚举信息
* @param name 枚举名称
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getEnum")
public Result<String> getEnum(@RequestParam("name") String name) {
return null;
}
/**
* 修改个人信息
* @return Result<String> 统一返回操作码及信息
*/
@PostMapping("/updatePersonInfo")
public Result<String> updatePersonInfo() {
return null;
}
/**
* 专家申请记录查看
* @return Result<List<String>> 统一返回操作码及信息
*/
@GetMapping("/getApplyList")
public Result<List<String>> getApplyLogListInfo() {
return null;
}
/**
* 专家退库申请
* @return Result<String> 统一返回操作码及信息
*/
@PostMapping("/exitBankApply")
public Result<String> exitBankApply() {
return null;
}
/**
* 专家续期申请
* @return Result<String> 统一返回操作码及信息
*/
@PostMapping("/renewalApply")
public Result<String> renewalApply() {
return null;
}
}
package com.cnooc.expertmanageminiapp.manage.controller;
import cn.hutool.json.JSONObject;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.manage.service.PortalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 小程序首页门户
* @author: FuHongZhang
* @date 2025-10-23 11:13
*/
@Slf4j
@RestController
@RequestMapping("/portal")
public class PortalController {
@Autowired
private PortalService portalService;
/**
* 获取首页信息
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getPortalInfo")
public Result<JSONObject> getPortalInfo() {
return Result.success();
}
/**
* 获取业务待办信息
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getAgendaList")
public Result<JSONObject> getBusinessAgendaInfo() {
// todo 获取当前登录人信息(后续考虑是否要把当前登录人id存入token)
return Result.success();
}
/**
* 获取我的消息
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getMyMessagesList")
public Result<JSONObject> getMyMessagesInfo() {
// todo 获取当前登录人信息(后续考虑是否要把当前登录人id存入token)
return Result.success();
}
}
package com.cnooc.expertmanageminiapp.manage.controller;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.manage.service.TrainingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 培训/考试
* @author: FuHongZhang
* @date 2025-10-24 10:52
*/
@Slf4j
@RestController
@RequestMapping("/training")
public class TrainingController {
@Autowired
private TrainingService trainingService;
/**
* 培训课程列表查询
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getCourseListInfo")
public Result<String> getCourseListInfo() {
return null;
}
/**
* 根据id查询课程详情
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getCourseById")
public Result<String> getCourseById() {
return null;
}
/**
* 课程详情-课节列表信息
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getCourseLessonById")
public Result<String> getCourseLessonById() {
return null;
}
/**
* 课节学习接口
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getCourseLessonStudy")
public Result<String> getCourseLessonStudy() {
return null;
}
/**
* 查询附件列表
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getAttachList")
public Result<String> getAttachList() {
return null;
}
/**
* 更新学习进度
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/updateLearnProgress")
public Result<String> updateLearnProgress() {
return null;
}
/**
* 考试列表查询
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getExamListInfo")
public Result<String> getExamListInfo() {
return null;
}
/**
* 查询考试试卷
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getExamPaper")
public Result<String> getExamPaper() {
return null;
}
/**
* 保存专家考试记录
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/saveExpertExamRecord")
public Result<String> saveExpertExamRecord() {
return null;
}
/**
* 查询考试答题集合列表
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getExamAnswerList")
public Result<String> getExamAnswerList() {
return null;
}
/**
* 获取小题列表
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getExamQuestionList")
public Result<String> getExamQuestionList() {
return null;
}
/**
* 保存考试试卷
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/submitExamPaper")
public Result<String> submitExamPaper() {
return null;
}
}
package com.cnooc.expertmanageminiapp.manage.controller;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.manage.service.VacateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 请假/休假
* @author: FuHongZhang
* @date 2025-10-23 16:24
*/
@Slf4j
@RestController
@RequestMapping("/vacate")
public class VacateController {
/**
* 紧急请假申请
* @return Result<String> 统一返回操作码及信息
*/
@PostMapping("/urgencyVacate")
public Result<String> urgencyVacate() {
return null;
}
/**
* 获取紧急请假历史记录
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getUrgencyVacateList")
public Result<String> getUrgencyVacateList() {
return null;
}
/**
* 个人休假申请
* @return Result<String> 统一返回操作码及信息
*/
@PostMapping("personVacate")
public Result<String> personVacate() {
return null;
}
/**
* 获取个人休假历史记录
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getPersonVacateList")
public Result<String> getPersonVacateList() {
return null;
}
/**
* 根据假单ID查询假单详情 todo 需要确认,紧急请假和个人请假是否是一张表?一个接口是否够用
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getVacateById")
public Result<String> getVacateById() {
return null;
}
/**
* 根据抽取码查询项目信息
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getVacateByExtractCode")
public Result<String> getVacateByExtractCode(String chouQuNum) {
return null;
}
}
package com.cnooc.expertmanageminiapp.manage.controller;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.manage.service.ViolationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 冻结/违规
* @author: FuHongZhang
* @date 2025-10-24 10:37
*/
@Slf4j
@RestController
@RequestMapping("/violation")
public class ViolationController {
@Autowired
private ViolationService violationService;
/**
* 查询冻结信息列表
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getFreezeListInfo")
public Result<String> getFreezeListInfo() {
return null;
}
//2 冻结信息详情查询接口
// /**
// * 冻结信息详情查询
// * @return Result<String> 统一返回操作码及信息
// */
// @GetMapping("/getFreezeInfoById")
// public Result<String> getFreezeInfoById() {
// return null;
// }
// //3 违规信息列表接口
/**
* 获取违规信息列表
* @return Result<String> 统一返回操作码及信息
*/
@GetMapping("/getViolationListInfo")
public Result<String> getViolationListInfo() {
return null;
}
//4 违规信息查询详情接口
// /**
// * 违规信息查询详情接口
// * @return Result<String> 统一返回操作码及信息
// */
// @GetMapping("/getViolationInfoById")
// public Result<String> getViolationInfoById() {
// return null;
// }
}
package com.cnooc.expertmanageminiapp.manage.entity.pojo;
import com.cnooc.expertmanageminiapp.common.utils.CommonUtil;
import java.util.List;
/**
*
* @author zhengkai
* @date - 2015年08月04日
*
*/
public class SysDict implements java.io.Serializable{
private static final long serialVersionUID = -1L;
private String dictGuid;//主键
private String typeName;//字典类型的名称
private String key;//暂未使用
private String value;//名称
private Integer sequence;//暂未使用
private Short isQiYong;//是否启用。1是启用 0是未启用
private String parentGuid;//父guid,保存父级别的dictGuid
private Long createTime;//创建时间
private String creatorGuid;//创建人Guid
private String creatorName;//创建人名称
private Long modifyTime;//修改时间
private String modifierGuid;//修改人Guid
private String modifierName;//修改人名称
private Boolean isDeleted;//是否删除
/**
* easyui treegrid用 选中或者不选中
*/
private Boolean checked;
/**
* easyui treegrid用 开启还是关闭 两个值 open closed
*/
private String state;
private List<SysDict> childrenDicts;
//父级名称+子级名称
private String parentName;
public Boolean getChecked() {
return checked;
}
public void setChecked(Boolean checked) {
this.checked = checked;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public SysDict(){
}
private String typeValue;
public String getTypeValue() {
return typeValue;
}
public void setTypeValue(String typeValue) {
this.typeValue = typeValue;
}
public String getDictGuid() {
return this.dictGuid;
}
public void setDictGuid(String value) {
this.dictGuid = value;
}
public String getTypeName() {
return this.typeName;
}
public void setTypeName(String value) {
this.typeName = value;
}
public String getKey() {
return this.key;
}
public void setKey(String value) {
this.key = value;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
public Integer getSequence() {
return this.sequence;
}
public void setSequence(Integer value) {
this.sequence = value;
}
public Short getIsQiYong() {
return this.isQiYong;
}
public void setIsQiYong(Short value) {
this.isQiYong = value;
}
public String getParentGuid() {
return this.parentGuid;
}
public void setParentGuid(String value) {
this.parentGuid = value;
}
public Long getCreateTime() {
return this.createTime;
}
public void setCreateTime(Long value) {
this.createTime = value;
}
public String getCreateTimeText() {
return CommonUtil.longTimeToString(this.createTime);
}
public String getCreatorGuid() {
return this.creatorGuid;
}
public void setCreatorGuid(String value) {
this.creatorGuid = value;
}
public String getCreatorName() {
return this.creatorName;
}
public void setCreatorName(String value) {
this.creatorName = value;
}
public Long getModifyTime() {
return this.modifyTime;
}
public void setModifyTime(Long value) {
this.modifyTime = value;
}
public String getModifyTimeText() {
return CommonUtil.longTimeToString(this.modifyTime);
}
public String getModifierGuid() {
return this.modifierGuid;
}
public void setModifierGuid(String value) {
this.modifierGuid = value;
}
public String getModifierName() {
return this.modifierName;
}
public void setModifierName(String value) {
this.modifierName = value;
}
public Boolean getIsDeleted() {
return this.isDeleted;
}
public void setIsDeleted(Boolean value) {
this.isDeleted = value;
}
public List<SysDict> getChildrenDicts() {
return childrenDicts;
}
public void setChildrenDicts(List<SysDict> childrenDicts) {
this.childrenDicts = childrenDicts;
}
public String getParentName() {
return parentName;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
}
package com.cnooc.expertmanageminiapp.manage.mapper;
import com.cnooc.expertmanageminiapp.manage.entity.pojo.ZhuanJiaInfo;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PersonInfoMapper {
ZhuanJiaInfo getExpertPersonInfo(@Param("zhuanJiaGuid") String zhuanJiaGuid);
}
package com.cnooc.expertmanageminiapp.manage.service;
public interface AssessBidService {
}
package com.cnooc.expertmanageminiapp.manage.service;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.manage.entity.pojo.ZhuanJiaInfo;
public interface PersonInfoService {
Result<ZhuanJiaInfo> getExpertPersonInfo();
}
package com.cnooc.expertmanageminiapp.manage.service;
public interface PortalService {
}
package com.cnooc.expertmanageminiapp.manage.service;
public interface TrainingService {
}
package com.cnooc.expertmanageminiapp.manage.service;
public interface VacateService {
}
package com.cnooc.expertmanageminiapp.manage.service;
public interface ViolationService {
}
package com.cnooc.expertmanageminiapp.manage.service.impl;
import com.cnooc.expertmanageminiapp.manage.service.AssessBidService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: FuHongZhang
* @date 2025-10-23 16:49
*/
@Slf4j
@Service
public class AssessBidServiceImpl implements AssessBidService {
}
package com.cnooc.expertmanageminiapp.manage.service.impl;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.common.utils.UserUtils;
import com.cnooc.expertmanageminiapp.manage.entity.pojo.ZhuanJiaInfo;
import com.cnooc.expertmanageminiapp.manage.mapper.PersonInfoMapper;
import com.cnooc.expertmanageminiapp.manage.service.PersonInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author: FuHongZhang
* @date 2025-10-23 15:53
*/
@Slf4j
@Service
public class PersonInfoServiceImpl implements PersonInfoService {
@Autowired
private PersonInfoMapper personInfoMapper;
@Override
public Result<ZhuanJiaInfo> getExpertPersonInfo() {
String zhuanJiaGuid = "010931d1-c8a7-483f-8421-461ddba6a457";
return Result.success(personInfoMapper.getExpertPersonInfo(zhuanJiaGuid));
}
}
package com.cnooc.expertmanageminiapp.manage.service.impl;
import com.cnooc.expertmanageminiapp.manage.service.PortalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: FuHongZhang
* @date 2025-10-23 15:44
*/
@Service
@Slf4j
public class PortalServiceImpl implements PortalService {
}
package com.cnooc.expertmanageminiapp.manage.service.impl;
import com.cnooc.expertmanageminiapp.manage.service.TrainingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: FuHongZhang
* @date 2025-10-24 10:52
*/
@Slf4j
@Service
public class TrainingServiceImpl implements TrainingService {
}
package com.cnooc.expertmanageminiapp.manage.service.impl;
import com.cnooc.expertmanageminiapp.manage.service.VacateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: FuHongZhang
* @date 2025-10-23 16:25
*/
@Slf4j
@Service
public class VacateServiceImpl implements VacateService {
}
package com.cnooc.expertmanageminiapp.manage.service.impl;
import com.cnooc.expertmanageminiapp.manage.service.VacateService;
import com.cnooc.expertmanageminiapp.manage.service.ViolationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author: FuHongZhang
* @date 2025-10-24 10:38
*/
@Slf4j
@Service
public class ViolationServiceImpl implements ViolationService {
}
package com.cnooc.expertmanageminiapp.system.Enum;
public interface BaseEnum<T> {
public T getCode();
public String name();
public String getDescription();
}
\ No newline at end of file
package com.cnooc.expertmanageminiapp.system.Enum;
/**
*
* @author Administrator
*民族(
01 汉族
02 蒙古族
03 回族
04 藏族
05 维吾尔族
06 苗族
07 彝族
08 壮族
09 布依族
10 朝鲜族
11 满族
12 侗族
13 瑶族
14 白族
15 土家族
16 哈尼族
17 哈萨克族
18 傣族
19 黎族
20 傈僳族
21 佤族
22 畲族
23 高山族
24 拉祜族
25 水族
26 东乡族
27 纳西族
28 景颇族
29 柯尔克孜族
30 土族
31 达斡尔族
32 仫佬族
33 羌族
34 布朗族
35 撒拉族
36 毛难族
37 仡佬族
38 锡伯族
39 阿昌族
40 普米族
41 塔吉克族
42 怒族
43 乌孜别克族
44 俄罗斯族
45 鄂温克族
46 崩龙族
47 保安族
48 裕固族
49 京族
50 塔塔尔族
51 独龙族
52 鄂伦春族
53 赫哲族
54 门巴族
55 珞巴族
56 基诺族
57 其他
58 外国血统)
*/
public enum MinZu implements BaseEnum<Short>{
HANZU((short)1,"汉族"),//招投标推送过来的,不受理的时候
MENGGUZU((short)2,"蒙古族"),
HUIZU((short)3,"回族"),
ZANGZU((short)4,"藏族"),
WEIWUERZU((short)5,"维吾尔族"),
MIAOZU((short)6,"苗族"),
YIZU((short)7,"彝族"),
ZHUANGZU((short)8,"壮族"),
BUYIZU((short)9,"布依族"),
CHAOXIANZU((short)10,"朝鲜族"),
MANZU((short)11,"满族"),
DONGZU((short)12,"侗族"),
YAOZU((short)13,"瑶族"),
BAIZU((short)14,"白族"),
TUJIAZU((short)15,"土家族"),
HANIZU((short)16,"哈尼族"),
HASAKEZU((short)17,"哈萨克族"),
DAIZU((short)18,"傣族"),
LIZU((short)19,"黎族"),
LISUZU((short)20,"傈僳族"),
WAZU((short)21,"佤族"),
SHEZU((short)22,"畲族"),
GAOSHANZU((short)23,"高山族"),
LAGUZU((short)24,"拉祜族"),
SHUIZU((short)25,"水族"),
DONGXIANGZU((short)26,"东乡族"),
NAXIZU((short)27,"纳西族"),
JINGPOZU((short)28,"景颇族"),
KEERKEZIZU((short)29,"柯尔克孜族"),
TUZU((short)30,"土族"),
DAHANERZU((short)31,"达斡尔族"),
MELAOZU((short)32,"仫佬族"),
QIANGZU((short)33,"羌族"),
BULANGZU((short)34,"布朗族"),
SALAZU((short)35,"撒拉族"),
MAONANZU((short)36,"毛难族"),
QILAOZU((short)37,"仡佬族"),
XIBOZU((short)38,"锡伯族"),
ACHANZU((short)39,"阿昌族"),
PUMIZU((short)40,"普米族"),
TAJIKEZU((short)41,"塔吉克族"),
NUZU((short)42,"怒族"),
WUZIBIEKEZU((short)43,"乌孜别克族"),
ELUOSIZU((short)44,"俄罗斯族"),
EWENKEZU((short)45,"鄂温克族"),
BENGLONGZU((short)46,"崩龙族"),
BAOANZU((short)47,"保安族"),
YUGUZU((short)48,"裕固族"),
JINGZU((short)49,"京族"),
TATAERZU((short)50,"塔塔尔族"),
DULONGZU((short)51,"独龙族"),
ELUNCHUNZU((short)52,"鄂伦春族"),
HEZEZU((short)53,"赫哲族"),
MENBAZU((short)54,"门巴族"),
LUOBAZU((short)55,"珞巴族"),
JINUOZU((short)56,"基诺族"),
QITA((short)57,"其他"),
WAIGUO((short)58,"外国血统")
;
private short code;
private String description;
private MinZu(Short _code, String description) {
this.code = _code;
this.description = description;
}
@Override
public Short getCode() {
return this.code;
}
@Override
public String getDescription() {
return description;
}
@Override
public String toString() {
return String.valueOf(this.code);
}
/**
* 通过枚举键获取枚举对象
* @param code
* @return
* @author zhengkai
* @date 2015年4月20日 下午12:24:04
*/
public static MinZu getEnum(Short code) {
for(MinZu autp : MinZu.values()) {
if(code.equals(autp.getCode())) {
return autp;
}
}
return null;
}
public static String getName(Short code) {
for(MinZu autp : MinZu.values()) {
if(code.equals(autp.getCode())) {
return autp.name();
}
}
return null;
}
//获取名称
public static String getDes(Short code){
for(MinZu autp : MinZu.values()){
if(code.equals(autp.getCode())){
return autp.getDescription();
}
}
return null;
}
}
/**
*
*/
package com.cnooc.expertmanageminiapp.system.Enum;
/**专家状态
* @author linyanhui
*
* 2016年1月18日 上午8:53:16
*/
public enum ZhuanJiaZhuangTai implements BaseEnum<Short> {
SHENQING((short)9,"申请"),
ZHENGCHANG((short)10,"正常"),
JIEPING((short)11,"解聘(可恢复)"),
ZHANTINGZIGE((short)12,"手动冻结"),
QINGJIA((short)13,"请假"),
HEIMINGDAN((short)14,"黑名单"),
JIEPINGYONGJIU((short)21,"解聘(永久)"),
ZHANTINGZIGEZIDONG((short)22,"自动暂停"),
ZHANTING((short)23,"暂停"),
ZHUCE((short)6,"注册"),
XUZHI((short)7,"须知同意"),
KAOSHI((short)8,"考试通过"),
SHANCHU((short)15,"删除"),;
private Short Code;
private String des;
private ZhuanJiaZhuangTai(short Code,String des){
this.Code = Code;
this.des = des;
}
/**
* @return
* @author linyanhui
* 2016年1月18日 上午8:54:48
*/
@Override
public Short getCode() {
return Code;
}
/**
* @return
* @author linyanhui
* 2016年1月18日 上午8:54:48
*/
@Override
public String getDescription() {
return des;
}
//通过属性获取对象
public static ZhuanJiaZhuangTai getZhuanJiaZhuangTai(Short code){
for(ZhuanJiaZhuangTai zhuanJiaZhuangTai : ZhuanJiaZhuangTai.values()){
if(code.equals(zhuanJiaZhuangTai.getCode())){
return zhuanJiaZhuangTai;
}
}
return null;
}
//获取名称
public static String getName(Short code){
for(ZhuanJiaZhuangTai zhuanJiaZhuangTai : ZhuanJiaZhuangTai.values()){
if(code.equals(zhuanJiaZhuangTai.getCode())){
return zhuanJiaZhuangTai.name();
}
}
return null;
}
//获取名称
public static String getDes(Short code){
if (code == null) {
return null;
}
for(ZhuanJiaZhuangTai zhuanJiaZhuangTai : ZhuanJiaZhuangTai.values()){
if(code.equals(zhuanJiaZhuangTai.getCode())){
return zhuanJiaZhuangTai.getDescription();
}
}
return null;
}
public static ZhuanJiaZhuangTai getEnum(Short code) {
for(ZhuanJiaZhuangTai zhuanJiaZhuangTai : ZhuanJiaZhuangTai.values()) {
if(code.equals(zhuanJiaZhuangTai.getCode())) {
return zhuanJiaZhuangTai;
}
}
return null;
}
}
package com.cnooc.expertmanageminiapp.system.controller;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.common.utils.ValidUtils;
import com.cnooc.expertmanageminiapp.system.entity.vo.LoginVO;
import com.cnooc.expertmanageminiapp.system.entity.vo.VerifyCodeVO;
import com.cnooc.expertmanageminiapp.system.service.LoginService;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @Author: FuHongZhang
* @CreateTime: 2025-09-18 15:03
*/
@Slf4j
@RestController
@RequestMapping("/sys")
public class LoginController {
@Autowired
private LoginService loginService;
/**
* 手机号验证码/身份证号密码 登录功能
* @param loginVO 登录表单
* @return Result<String> 统一返回操作码及信息
*/
@PostMapping("/login")
public Result<String> login(@Validated @RequestBody LoginVO loginVO) {
// 校验loginType 不为空
return loginService.login(loginVO);
}
/**
* 获取验证码
* @param phoneNumber 手机号必传
* @return Result<Integer> 统一返回操作结果及验证码
*/
@GetMapping("/sendCode/{phoneNumber}")
public Result<String> sendCode(@PathVariable String phoneNumber) {
log.info("获取验证码的手机号: {}", phoneNumber);
return loginService.sendPhoneCode(phoneNumber);
}
@PostMapping("/verifyCode")
public Result<String> verifyCode(@RequestBody VerifyCodeVO codeVO) {
return loginService.verifyCode(codeVO);
}
/**
* 账号修改
* @param loginVO
* @return
*/
public Result<String> changePass(@RequestBody LoginVO loginVO) {
return loginService.changePass(loginVO);
}
}
package com.cnooc.expertmanageminiapp.system.controller;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil;
import com.cnooc.expertmanageminiapp.common.exception.enums.GlobalErrorCodeConstants;
import com.cnooc.expertmanageminiapp.common.utils.ValidUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.imageio.ImageIO;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 图形验证码控制
* @Author: FuHongZhang
* @CreateTime: 2025-09-25 14:02
*/
@Slf4j
@RestController
@RequestMapping("/verify")
public class VerifyCodeController {
// 验证码配置参数
private static final int WIDTH = 150;
private static final int HEIGHT = 50;
private static final int CODE_LENGTH = 4;
private static final int INTERFERENCE_COUNT = 3;
private static final int EXPIRE_MINUTES = 1;
private static final String CAPTCHA_KEY = "CAPTCHA_";
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 获取图片验证码
*
* @return ResponseEntity 返回验证码ID和图片的base64位码
*/
@GetMapping("/getImgCode")
public ResponseEntity<Map<String, String>> getImgCode() throws IOException {
// 1. 生成验证码
ShearCaptcha captcha = new ShearCaptcha(WIDTH, HEIGHT, CODE_LENGTH, INTERFERENCE_COUNT);
String code = captcha.getCode();
// 2. 生成唯一验证码ID
String captchaId = IdUtil.simpleUUID();
// 3. 保存验证码到Redis
redisTemplate.opsForValue().set(CAPTCHA_KEY + captchaId, code, EXPIRE_MINUTES, TimeUnit.MINUTES);
// 4. 将验证码图片转为Base64
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(captcha.getImage(), "png", outputStream);
String base64Image = "data:image/png;base64," + Base64.encode(outputStream.toByteArray());
// 5. 构建响应
Map<String, String> response = new HashMap<>();
response.put("captchaId", captchaId);
response.put("image", base64Image);
return ResponseEntity.ok()
.header(HttpHeaders.CACHE_CONTROL, "no-store, no-cache")
.body(response);
}
/**
* 验证图片验证码
*/
@PostMapping("/verifyImgCode")
public ResponseEntity<Map<String, Object>> verifyCaptcha(
@RequestParam String captchaId,
@RequestParam String inputCode) {
Map<String, Object> result = new HashMap<>();
// 1. 从缓存中获取验证码
String storedCode = redisTemplate.opsForValue().get(CAPTCHA_KEY + captchaId);
ValidUtils.isNotNull(storedCode, GlobalErrorCodeConstants.CODE_REDIS_KEY);
// 2. 验证验证码
ValidUtils.isTrue(storedCode.equals(inputCode), GlobalErrorCodeConstants.CAPTCHA_EXPIRED);
// 3. 验证成功,删除Session中的验证码
redisTemplate.delete(CAPTCHA_KEY + captchaId);
result.put("success", true);
result.put("message", "验证成功");
return ResponseEntity.ok(result);
}
}
package com.cnooc.expertmanageminiapp.system.entity.pojo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author: FuHongZhang
* @date 2025-10-30 18:00
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ZhuanJiaUser {
private static final long serialVersionUID = -1L;
private String zhuanJiaGuid;
private String zhuanJiaShiXiangGuid;
private String zhuanJiaName;
private String zhuanJiaCode;
private String shenFenZheng;
private String mobile;
private Short zhuanJiaZhuangTai;
private Boolean shiFouYiFaZhuanJia;
private String suoShuBuMeng;//所在部门
}
package com.cnooc.expertmanageminiapp.system.entity.vo;
import lombok.*;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
/**
* 接收登录的form表单数据
* @Author: FuHongZhang
* @CreateTime: 2025-09-18 15:11
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LoginVO {
private String phoneNumber;
private String phoneCode;
private String idNumber;
private String password;
@Max(value = 2, message = "登录类型只能是1,手机验证码登录 2.身份证密码登录")
@Min(value = 1)
private Integer loginType;
}
package com.cnooc.expertmanageminiapp.system.entity.vo;
import java.io.Serializable;
/**
* @author: FuHongZhang
* @date 2025-10-22 17:03
*/
public class VerifyCodeVO implements Serializable {
private String phoneNumber;
private String phoneCode;
}
package com.cnooc.expertmanageminiapp.system.mapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @Author: FuHongZhang
* @CreateTime: 2025-09-18 15:23
*/
@Mapper
public interface LoginMapper{
}
package com.cnooc.expertmanageminiapp.system.service;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.system.entity.vo.LoginVO;
import com.cnooc.expertmanageminiapp.system.entity.vo.VerifyCodeVO;
public interface LoginService {
Result<String> login(LoginVO loginVO);
Result<String> sendPhoneCode(String phoneNumber);
Result<String> changePass(LoginVO loginVO);
Result<String> verifyCode(VerifyCodeVO codeVO);
}
package com.cnooc.expertmanageminiapp.system.service.impl;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdcardUtil;
import com.cnooc.expertmanageminiapp.common.constant.TokenConstants;
import com.cnooc.expertmanageminiapp.common.exception.BusinessException;
import com.cnooc.expertmanageminiapp.common.response.Result;
import com.cnooc.expertmanageminiapp.common.utils.JwtUtils;
import com.cnooc.expertmanageminiapp.common.utils.ValidUtils;
import com.cnooc.expertmanageminiapp.system.entity.vo.LoginVO;
import com.cnooc.expertmanageminiapp.system.entity.vo.VerifyCodeVO;
import com.cnooc.expertmanageminiapp.system.mapper.LoginMapper;
import com.cnooc.expertmanageminiapp.system.service.LoginService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.UUID;
/**
* @Author: songYuHang
* @CreateTime: 2025-09-18 15:23
*/
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
@Autowired
private LoginMapper loginMapper;
@Autowired
private StringRedisTemplate redisTemplate;
/** 身份证密码登录 */
private static final int ID_NUMBER_PASSWORD = 1;
/** 手机验证码登录 */
private static final int PHONE_CODE = 2;
/**
* 登录逻辑
* @param loginVO 登录
* @return Result<String> token
*/
@Override
public Result<String> login(LoginVO loginVO) {
log.info("开始执行登录逻辑");
String token;
switch (loginVO.getLoginType()) {
case ID_NUMBER_PASSWORD:
token = idNumberLogin(loginVO);
break;
case PHONE_CODE:
token = phoneCodeLogin(loginVO);
break;
default:
throw new BusinessException("请选择登录类型");
}
return Result.success(token);
}
/**
* 获取验证码逻辑
* @param phoneNumber 手机号
* @return Result<String> token
*/
@Override
public Result<String> sendPhoneCode(String phoneNumber) {
log.info("开始执行获取验证码逻辑");
ValidUtils.isText(phoneNumber, "请输入手机号");
ValidUtils.isTrue(Validator.isMobile(phoneNumber), "请输入正确的手机号");
//待确认,验证码下发是调用第三方平台吗
return Result.success("验证码已发送");
}
@Override
public Result<String> changePass(LoginVO loginVO) {
log.info("开始执行修改密码逻辑");
return Result.success();
}
@Override
public Result<String> verifyCode(VerifyCodeVO codeVO) {
log.info("手机验证码验证逻辑");
return null;
}
/**
* 身份证密码登录
* @param loginVO 登录参数
* @return token
*/
private String idNumberLogin(LoginVO loginVO) {
log.info("开始执行身份证登录逻辑");
ValidUtils.isText(loginVO.getIdNumber(), "请输入身份证号");
ValidUtils.isText(loginVO.getPassword(), "请输入密码");
ValidUtils.isTrue(IdcardUtil.isValidCard(loginVO.getIdNumber()), "请输入正确的身份证号");
//1.需要去库中查询,是否存在
//2.存在校验密码
//3.生成相应的uuid作为redis的key
// // todo userid
String uuidKey = UUID.randomUUID().toString();
String token = JwtUtils.createToken(1,uuidKey);
tokenSetRedis(token, uuidKey);
//6.返回token
return token;
}
/**
* 手机验证码登录
* @param loginVO 手机号登录参数
* @return token
*/
private String phoneCodeLogin(LoginVO loginVO) {
log.info("开始执行手机验证码登录逻辑");
ValidUtils.isText(loginVO.getPhoneNumber(), "请输入手机号");
ValidUtils.isText(loginVO.getPhoneCode(), "请输入验证码");
ValidUtils.isTrue(Validator.isMobile(loginVO.getPhoneNumber()), "请输入正确格式的手机号");
//1.根据手机号去库中查询是否存在
//2.存在校验验证码
//3.生成相应的uuid作为redis的key
// todo userid
String uuidKey = UUID.randomUUID().toString();
String token = JwtUtils.createToken(1,uuidKey);
tokenSetRedis(token, uuidKey);
return token;
}
/**
* 缓存存入token
* @param token token
* @param uuidKey uuidKey
*/
private void tokenSetRedis(String token, String uuidKey) {
String redisTokenKey = TokenConstants.TOKEN_KEY_ + uuidKey;
redisTemplate.opsForValue().set(redisTokenKey, token, Duration.ofHours(24));
}
}
package com.cnooc.expertmanageminiapp.test;
import com.cnooc.expertmanageminiapp.common.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: songYuHang
* @CreateTime: 2025-09-16 14:16
*/
@RestController
@RequestMapping("text")
@Slf4j
public class a {
@GetMapping("text1")
// @Operation(summary = "测试接口", description = "测试接口")
public Result<String> geta () {
log.info("1111");
return Result.success("访问成功");
}
@GetMapping("text2")
public Result<Long> getb () {
long l = Runtime.getRuntime().totalMemory();
log.info("堆内存大小: {}", l);
return Result.success(l);
}
}
server: server:
port: 9090 port: 9090
servlet:
context-path: /miniapp
# ssl:
# key-store: classpath:server.p12 # 证书文件路径
# key-store-password: 123456 # 证书密码
# key-store-type: PKCS12 # 证书类型
# key-alias: tomcat # 证书别名
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: cgglapplicationdev
password: Cwgxs4N%Y8tS!VA
url: jdbc:mysql://10.77.64.203:30975/saas_zhuanjia?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
data:
redis:
host: localhost
port: 6379
password:
timeout: 2000ms
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.cnooc.expertmanageminiapp.manage.entity
type-handlers-package: com.expert.manage.handler
configuration: #mybatis全局配置
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
cache-enabled: true
\ No newline at end of file
<?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.cnooc.expertmanageminiapp.manage.mapper.PersonInfoMapper">
<sql id="zhuanjiaInfoFields">
zhuanjia_guid,
zhuanjia_shixing_guid
</sql>
<resultMap id="zhuanjiaInfoMap" type="com.cnooc.expertmanageminiapp.manage.entity.pojo.ZhuanJiaInfo">
<id property="zhuanJiaGuid" column="zhuanjia_guid"/>
<!-- 普通字段映射 -->
<result property="zhuanJiaShiXiangGuid" column="zhuanjia_shixiang_guid"/>
</resultMap>
<select id="getExpertPersonInfo"
resultMap="zhuanjiaInfoMap" parameterType="String">
select
<include refid="zhuanjiaInfoFields"/>
from zhuanjia_info
where isDeleted = 0 and zhuanjia_guid = #{zhuanJiaGuid}
</select>
</mapper>
\ No newline at end of file
<?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.cnooc.expertmanageminiapp.system.mapper.LoginMapper">
</mapper>
\ No newline at end of file
package com.cnooc.expertmanageminiapp;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ExpertManageMiniappApplicationTests {
@Test
void contextLoads() {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment