OCT 1. SpringBoot 版本切换到 SpringBoot2

This commit is contained in:
黄昕 2023-10-30 19:14:47 +08:00
parent 3a65ae27ad
commit e24e1216f1
31 changed files with 889 additions and 71 deletions

13
pom.xml
View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<version>2.7.17</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cmhi</groupId>
@ -14,7 +14,7 @@
<name>game_database_service</name>
<description>game_database_service</description>
<properties>
<java.version>21</java.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
@ -64,7 +64,7 @@
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.2</version>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
@ -130,13 +130,18 @@
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.2</version>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.4.16</version>
</dependency>
</dependencies>
<build>

View File

@ -334,16 +334,31 @@ public enum ErrorCode implements BaseEnum {
* @return the http code
*/
public int getHttpCode() {
return switch (this) {
case ERR_OK -> HttpServletResponse.SC_OK;
case ERR_SYSTEMEXCEPTION, ERR_PARAMEXCEPTION -> HttpServletResponse.SC_EXPECTATION_FAILED;
case ERR_TOKENTIMEOUT, ERR_REQTIMEOUT -> HttpServletResponse.SC_REQUEST_TIMEOUT;
case ERR_UNTRUSTTOKEN, ERR_UNTRUSTHOST, ERR_LOGOUT -> HttpServletResponse.SC_UNAUTHORIZED;
case ERR_MISSAUTHHEAD, ERR_PARAMS, ERR_INPUTFORMAT, ERR_INPUTMISS -> HttpServletResponse.SC_BAD_REQUEST;
case ERR_UNSUPPORT -> HttpServletResponse.SC_METHOD_NOT_ALLOWED;
case ERR_UNKNOWNINTERFACE -> HttpServletResponse.SC_NOT_FOUND;
default -> HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
};
switch (this) {
case ERR_OK:
return HttpServletResponse.SC_OK;
case ERR_SYSTEMEXCEPTION:
case ERR_PARAMEXCEPTION:
return HttpServletResponse.SC_EXPECTATION_FAILED;
case ERR_TOKENTIMEOUT:
case ERR_REQTIMEOUT:
return HttpServletResponse.SC_REQUEST_TIMEOUT;
case ERR_UNTRUSTTOKEN:
case ERR_UNTRUSTHOST:
case ERR_LOGOUT:
return HttpServletResponse.SC_UNAUTHORIZED;
case ERR_MISSAUTHHEAD:
case ERR_PARAMS:
case ERR_INPUTFORMAT:
case ERR_INPUTMISS:
return HttpServletResponse.SC_BAD_REQUEST;
case ERR_UNSUPPORT:
return HttpServletResponse.SC_METHOD_NOT_ALLOWED;
case ERR_UNKNOWNINTERFACE:
return HttpServletResponse.SC_NOT_FOUND;
default:
return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}
}
/**

View File

@ -0,0 +1,11 @@
package com.cmhi.gds.common;
public class GlobalConfigure {
private GlobalConfigure() {
throw new AssertionError("Instantiating utility class.");
}
public static volatile boolean CHECK_PROTO_REQUEST_TIMEOUT = false;
public static volatile long REQUEST_TIMEOUT_MS = 5 * 1000;
}

View File

@ -3,16 +3,20 @@ package com.cmhi.gds.controller;
import com.cmhi.gds.common.ErrorCode;
import com.cmhi.gds.pojo.dto.protocol.base.ProtocolReqDTO;
import com.cmhi.gds.pojo.dto.protocol.base.ProtocolRespDTO;
import com.cmhi.gds.pojo.dto.protocol.info.GameInfoContent;
import com.cmhi.gds.pojo.dto.protocol.info.GameInfoDetail;
import com.cmhi.gds.pojo.dto.protocol.info.GameListSummary;
import com.cmhi.gds.pojo.dto.protocol.info.GameServerReq;
import com.cmhi.gds.pojo.dto.protocol.info.GameServerRsp;
import com.cmhi.gds.pojo.dto.protocol.info.GetGameInfoDetailReq;
import com.cmhi.gds.pojo.dto.protocol.info.GetGamesInfoRsp;
import com.cmhi.gds.pojo.dto.protocol.info.GetGamesSummaryRsp;
import com.cmhi.gds.pojo.vo.GameTableItems;
import com.cmhi.gds.pojo.dto.protocol.info.ReportGameServerReq;
import com.cmhi.gds.pojo.vo.GameTableItemsDetail;
import com.cmhi.gds.pojo.vo.GameTableItemsSummary;
import com.cmhi.gds.security.annotation.Decryption;
import com.cmhi.gds.security.annotation.Encryption;
import com.cmhi.gds.service.GameDatabaseServiceService;
import com.cmhi.gds.validation.group.ValidGroups;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
@ -23,8 +27,12 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Controller
@RequestMapping(value = "/gameinfo")
@ -40,17 +48,16 @@ public class GameDatabaseInfoController {
@GetMapping("gamelistsummary")
@ResponseBody
public ProtocolRespDTO<GetGamesSummaryRsp> getGameListSummary() {
GetGamesSummaryRsp rspInfo = GetGamesSummaryRsp.builder()
.items(new ArrayList<>())
.build();
List<GameTableItems> gameList = gameDatabaseServiceService.getGameTableSummaryItems();
List<GameTableItemsSummary> gameList = gameDatabaseServiceService.getGameTableSummaryItems();
if (!gameList.isEmpty()) {
for (GameTableItems v : gameList) {
for (GameTableItemsSummary v : gameList) {
GameListSummary item = GameListSummary.builder()
.gameId(v.getGameId())
.build();
@ -74,11 +81,69 @@ public class GameDatabaseInfoController {
return ProtocolRespDTO.result(ErrorCode.ERR_OK, rspInfo);
}
@PostMapping("gamelistDetails")
@ResponseBody
public ProtocolRespDTO<GetGamesInfoRsp> getGameInfoDetails(@Validated(ValidGroups.AddGameServiceValid.class)
@RequestBody ProtocolReqDTO<GetGameInfoDetailReq> mr) {
GetGamesInfoRsp rspInfo = GetGamesInfoRsp.builder().build();
List<GameInfoContent> gameContent = new ArrayList<>();
//获取TaskId列表
List<Long> reqTaskIds = Optional.ofNullable(mr.getMsgContent().getItems())
.orElse(new ArrayList<>());
List<GameTableItemsDetail> ret = gameDatabaseServiceService.getGameTableItems(reqTaskIds);
// 不存在的ID
reqTaskIds.stream()
.filter(v -> ret.stream().noneMatch(k -> k.getGameId().equals(v)))
.forEach(v -> {
GameInfoContent gi = GameInfoContent.builder().build();
gi.setGameId(v);
gi.setStatus(ErrorCode.ERR_NOSUCHTASK.getCode());
gi.setMessage(new String[]{ErrorCode.ERR_NOSUCHTASK.getMsg()});
gameContent.add(gi);
});
for (GameTableItemsDetail v : ret) {
GameInfoContent gi = GameInfoContent.builder()
.gameId(v.getGameId())
.company(v.getCompany())
.name(v.getName())
.gamesInfo(new ArrayList<>())
.build();
gi.setStatus(ErrorCode.ERR_OK.getCode());
gi.setMessage(new String[]{ErrorCode.ERR_OK.getMsg()});
v.getGameDetails().forEach(k -> {
GameInfoDetail gd = GameInfoDetail.builder()
.gameInfoId(k.getGameInfoId())
.version(k.getVersion())
.gameFileName(k.getFilename())
.md5sum(k.getMd5sum())
.build();
gi.getGamesInfo().add(gd);
});
gameContent.add(gi);
}
rspInfo.getItems().addAll(gameContent.stream().sorted(Comparator.comparingLong(GameInfoContent::getGameId))
.collect(Collectors.toList()));
rspInfo.setStatus(ErrorCode.ERR_OK.getCode());
rspInfo.setMessage(new String[]{ErrorCode.ERR_OK.getMsg()});
return ProtocolRespDTO.result(ErrorCode.ERR_OK, rspInfo);
}
@PostMapping("/gamedata")
@ResponseBody
public ProtocolRespDTO<GameServerRsp> reportGameServiceData(
@Validated(ValidGroups.AddGameServiceValid.class)
@RequestBody ProtocolReqDTO<GameServerReq> mr) {
@RequestBody ProtocolReqDTO<ReportGameServerReq> mr) {
GameServerRsp rspInfo = new GameServerRsp();
rspInfo.setItems(new ArrayList<>());
//

View File

@ -44,7 +44,6 @@ public class GlobalExceptionHandler {
String reqPath = req.getRequestURI();
String reqIp = req.getRemoteAddr();
String reqToken = req.getHeader("Authorization");
if (reqToken != null && !reqToken.isEmpty()) {
reqToken = reqToken.replace(ConstValue.STRING_HTTP_AUTH_HEAD, "");
}
@ -66,10 +65,9 @@ public class GlobalExceptionHandler {
}
sb.append("]");
log.error("""
Interface [{}] request <{}> from {}, token = <{}>
+++ Request: {}
--- Verify params failed: {}""",
log.error("Interface [{}] request <{}> from {}, token = <{}>\n" +
"+++ Request: {}\n" +
"--- Verify params failed: {}",
reqType, reqPath, reqIp, reqToken, Helper.inputStream2String(req.getInputStream()), sb);
} catch (Exception ignored) {
}
@ -109,14 +107,12 @@ public class GlobalExceptionHandler {
String reqPath = req.getRequestURI();
String reqIp = req.getRemoteAddr();
String reqToken = req.getHeader("Authorization");
if (reqToken != null && !reqToken.isEmpty()) {
reqToken = reqToken.replace(ConstValue.STRING_HTTP_AUTH_HEAD, "");
}
log.error("""
Interface [{}] request <{}> from {}, token = <{}>
+++ Request: {}
--- Verify params failed: {}""",
log.error("Interface [{}] request <{}> from {}, token = <{}>\n" +
"+++ Request: {}\n" +
"--- Verify params failed: {}",
reqType, reqPath, reqIp, reqToken, Helper.inputStream2String(req.getInputStream()),
ex.getMessage() == null ? ex.getDescription() : ex.getMessage());
} catch (Exception ignored) {
@ -163,10 +159,9 @@ public class GlobalExceptionHandler {
if (reqToken != null && !reqToken.isEmpty()) {
reqToken = reqToken.replace(ConstValue.STRING_HTTP_AUTH_HEAD, "");
}
log.error("""
Interface [{}] request <{}> from {}, token = <{}>
+++ Request: {}
--- Verify params failed: {}""",
log.error("Interface [{}] request <{}> from {}, token = <{}>\n" +
"+++ Request: {}\n" +
"--- Verify params failed: {}",
reqType, reqPath, reqIp, reqToken, Helper.inputStream2String(req.getInputStream()),
ex.getMessage());
} catch (Exception ignored) {

View File

@ -0,0 +1,106 @@
package com.cmhi.gds.interceptor;
import com.cmhi.gds.misc.Helper;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
/**
* The type Request body cache wrapper.
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
public class RequestBodyCacheWrapper extends HttpServletRequestWrapper {
/**
* The Body.
*/
private final byte[] body;
/**
* Instantiates a new Request body cache wrapper.
*
* @param request the request
*/
public RequestBodyCacheWrapper(HttpServletRequest request) {
super(request);
// 将body数据存储起来
String bodyStr = getBodyString(request);
body = bodyStr.getBytes(Charset.defaultCharset());
}
/**
* Gets body string.
*
* @param request the request
* @return the body string
*/
public String getBodyString(final ServletRequest request) {
try {
return Helper.inputStream2String(request.getInputStream());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Gets body string.
*
* @return the body string
*/
public String getBodyString() {
final InputStream inputStream = new ByteArrayInputStream(body);
return Helper.inputStream2String(inputStream);
}
/**
* Gets reader.
*
* @return the reader
*/
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
/**
* Gets input stream.
*
* @return the input stream
*/
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return inputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}

View File

@ -0,0 +1,52 @@
package com.cmhi.gds.interceptor;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* The type Request body filter.
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
@WebFilter(filterName = "RequestBodyFilter", urlPatterns = "/*")
public class RequestBodyFilter implements Filter {
/**
* Init.
*
* @param filterConfig the filter config
*/
@Override
public void init(FilterConfig filterConfig) {
}
/**
* Destroy.
*/
@Override
public void destroy() {
}
/**
* Do filter.
*
* @param request the request
* @param response the response
* @param filterChain the filter chain
* @throws IOException the io exception
* @throws ServletException the servlet exception
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = new RequestBodyCacheWrapper((HttpServletRequest) request);
filterChain.doFilter(requestWrapper, response);
}
}

View File

@ -0,0 +1,104 @@
package com.cmhi.gds.interceptor;
import com.cmhi.gds.security.annotation.Decryption;
import com.cmhi.gds.service.ProtocolSecurityService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Type;
/**
* The type Request protocol security.
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
@Slf4j
@RestControllerAdvice
public class RequestProtocolSecurity implements RequestBodyAdvice {
/**
* The Protocol security service.
*/
@Resource
private ProtocolSecurityService protocolSecurityService;
/**
* Supports boolean.
*
* @param methodParameter the method parameter
* @param type the type
* @param aClass the a class
* @return the boolean
*/
@Override
public boolean supports(@NotNull MethodParameter methodParameter,
@NotNull Type type,
@NotNull Class<? extends HttpMessageConverter<?>> aClass) {
return methodParameter.getContainingClass().isAnnotationPresent(Decryption.class)
|| methodParameter.hasMethodAnnotation(Decryption.class);
}
/**
* Before body read http input message.
*
* @param httpInputMessage the http input message
* @param methodParameter the method parameter
* @param type the type
* @param aClass the a class
* @return the http input message
*/
@Override
@NotNull
public HttpInputMessage beforeBodyRead(@NotNull HttpInputMessage httpInputMessage,
@NotNull MethodParameter methodParameter,
@NotNull Type type,
@NotNull Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
return protocolSecurityService.decryptProtocol(httpInputMessage);
}
/**
* Handle empty body object.
*
* @param o the o
* @param httpInputMessage the http input message
* @param methodParameter the method parameter
* @param type the type
* @param aClass the a class
* @return the object
*/
@Override
public Object handleEmptyBody(Object o,
@NotNull HttpInputMessage httpInputMessage,
@NotNull MethodParameter methodParameter,
@NotNull Type type,
@NotNull Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
/**
* After body read object.
*
* @param o the o
* @param httpInputMessage the http input message
* @param methodParameter the method parameter
* @param type the type
* @param aClass the a class
* @return the object
*/
@Override
@NotNull
public Object afterBodyRead(@NotNull Object o,
@NotNull HttpInputMessage httpInputMessage,
@NotNull MethodParameter methodParameter,
@NotNull Type type,
@NotNull Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
}

View File

@ -0,0 +1,83 @@
package com.cmhi.gds.interceptor;
import com.cmhi.gds.common.ProtoCryptoType;
import com.cmhi.gds.common.SecurityConfigValue;
import com.cmhi.gds.pojo.dto.protocol.base.ProtocolRespDTO;
import com.cmhi.gds.security.annotation.Encryption;
import com.cmhi.gds.service.ProtocolSecurityService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.annotation.Resource;
/**
* The type Response protocol security.
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
@Slf4j
@RestControllerAdvice
public class ResponseProtocolSecurity implements ResponseBodyAdvice<Object> {
/**
* The Protocol security service.
*/
@Resource
private ProtocolSecurityService protocolSecurityService;
/**
* Supports boolean.
*
* @param methodParameter the method parameter
* @param aClass the a class
* @return the boolean
*/
@Override
public boolean supports(@NotNull MethodParameter methodParameter,
@NotNull Class<? extends HttpMessageConverter<?>> aClass) {
return methodParameter.getContainingClass().isAnnotationPresent(Encryption.class)
|| methodParameter.hasMethodAnnotation(Encryption.class);
}
/**
* Before body write object.
*
* @param o the o
* @param methodParameter the method parameter
* @param mediaType the media type
* @param aClass the a class
* @param serverHttpRequest the server http request
* @param serverHttpResponse the server http response
* @return the object
*/
@Override
@NotNull
public Object beforeBodyWrite(Object o,
@NotNull MethodParameter methodParameter,
@NotNull MediaType mediaType,
@NotNull Class<? extends HttpMessageConverter<?>> aClass,
@NotNull ServerHttpRequest serverHttpRequest,
@NotNull ServerHttpResponse serverHttpResponse) {
if (SecurityConfigValue.SECURITY_PROTOCOL_TYPE == ProtoCryptoType.CRYPTO_NONE.getCode()) {
if (o instanceof ProtocolRespDTO) {
serverHttpResponse.setStatusCode(org.springframework.http.HttpStatus.valueOf(((ProtocolRespDTO<?>) o).getCode()));
}
return o;
} else {
ProtocolRespDTO<String> rspInfo = protocolSecurityService.encryptProtocol(o,
SecurityConfigValue.SECURITY_PROTOCOL_TYPE);
serverHttpResponse.setStatusCode(org.springframework.http.HttpStatus.valueOf(rspInfo.getCode()));
return rspInfo;
}
}
}

View File

@ -1,9 +1,12 @@
package com.cmhi.gds.manager;
import com.cmhi.gds.pojo.entry.GameTableSummary;
import com.cmhi.gds.pojo.vo.GameTableItemsDetail;
import com.cmhi.gds.pojo.vo.GameTableSummary;
import java.util.List;
public interface GameDatabaseServiceManager {
List<GameTableSummary> getGameTableSummary();
List<GameTableItemsDetail> getGameTableDetails(List<Long> gameId);
}

View File

@ -4,11 +4,12 @@ import com.cmhi.gds.manager.GameDatabaseServiceManager;
import com.cmhi.gds.mapper.GameInfoMapper;
import com.cmhi.gds.mapper.GameServerMapper;
import com.cmhi.gds.mapper.GameTableMapper;
import com.cmhi.gds.pojo.entry.GameTableSummary;
import jakarta.annotation.Resource;
import com.cmhi.gds.pojo.vo.GameTableItemsDetail;
import com.cmhi.gds.pojo.vo.GameTableSummary;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Component
@ -27,4 +28,9 @@ public class GameDatabaseServiceManagerImpl implements GameDatabaseServiceManage
public List<GameTableSummary> getGameTableSummary() {
return gameTableMapper.selectAllGameSummary();
}
@Override
public List<GameTableItemsDetail> getGameTableDetails(List<Long> gameId) {
return gameTableMapper.selectAllGameDetailById(gameId);
}
}

View File

@ -1,7 +1,9 @@
package com.cmhi.gds.mapper;
import com.cmhi.gds.pojo.entry.GameTable;
import com.cmhi.gds.pojo.entry.GameTableSummary;
import com.cmhi.gds.pojo.vo.GameTableItemsDetail;
import com.cmhi.gds.pojo.vo.GameTableSummary;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -9,4 +11,6 @@ public interface GameTableMapper {
List<GameTable> selectAll();
List<GameTableSummary> selectAllGameSummary();
List<GameTableItemsDetail> selectAllGameDetailById(@Param("idList") List<Long> idList);
}

View File

@ -18,7 +18,6 @@ import javax.validation.constraints.NotNull;
*/
@Data
@NoArgsConstructor
@JsonPropertyOrder({"ver", "cryptoType", "timeStamp", "msgContent"})
public class BaseProtocolDTO<T> {
/**

View File

@ -1,22 +1,26 @@
package com.cmhi.gds.pojo.dto.protocol.info;
import com.cmhi.gds.pojo.dto.protocol.base.BaseRespStatus;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonPropertyOrder({"gameId", "gamesInfo"})
@JsonPropertyOrder({"gameId", "name", "company", "gamesInfo", "status", "message"})
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GameInfoContent {
private Long gameId;
public class GameInfoContent extends BaseRespStatus {
List<GameInfoDetail> gamesInfo;
private Long gameId;
private String name;
private String company;
}

View File

@ -14,6 +14,7 @@ import lombok.NoArgsConstructor;
@JsonPropertyOrder({"gameFileName", "md5sum", "version"})
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GameInfoDetail {
private Long gameInfoId;
private String gameFileName;
private String md5sum;
private String version;

View File

@ -0,0 +1,23 @@
package com.cmhi.gds.pojo.dto.protocol.info;
import com.cmhi.gds.validation.group.ValidGroups;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class GetGameInfoDetailReq {
@NotNull(message = "items 设备列表不能为空", groups = ValidGroups.AddGameServiceValid.class)
@Size(min = 1, message = "items 至少需要有一个元素", groups = ValidGroups.AddGameServiceValid.class)
@Valid
private List<Long> items;
}

View File

@ -1,8 +1,6 @@
package com.cmhi.gds.pojo.dto.protocol.info;
import com.cmhi.gds.validation.group.ValidGroups;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -17,9 +15,7 @@ import java.util.List;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonPropertyOrder({"gameId", "services"})
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GameServerReq {
public class ReportGameServerReq {
@NotNull(message = "items 设备列表不能为空", groups = ValidGroups.AddGameServiceValid.class)
@Size(min = 1, message = "items 至少需要有一个元素", groups = ValidGroups.AddGameServiceValid.class)
@Valid

View File

@ -12,7 +12,6 @@ import tk.mybatis.mapper.code.Style;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serial;
import java.io.Serializable;
@Data
@ -27,7 +26,6 @@ public class GameInfo implements Serializable {
/**
* The constant serialVersionUID.
*/
@Serial
private static final long serialVersionUID = 1L;
/**

View File

@ -13,7 +13,6 @@ import tk.mybatis.mapper.code.Style;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serial;
import java.io.Serializable;
@Data
@ -28,7 +27,7 @@ public class GameServer implements Serializable {
/**
* The constant serialVersionUID.
*/
@Serial
private static final long serialVersionUID = 1L;
/**

View File

@ -12,7 +12,6 @@ import tk.mybatis.mapper.code.Style;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serial;
import java.io.Serializable;
@Data
@ -27,7 +26,6 @@ public class GameTable implements Serializable {
/**
* The constant serialVersionUID.
*/
@Serial
private static final long serialVersionUID = 1L;
/**

View File

@ -0,0 +1,22 @@
package com.cmhi.gds.pojo.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GameDetail {
private Long gameInfoId;
private String version;
private String filename;
private String md5sum;
}

View File

@ -1,4 +1,4 @@
package com.cmhi.gds.pojo.entry;
package com.cmhi.gds.pojo.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;

View File

@ -0,0 +1,24 @@
package com.cmhi.gds.pojo.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GameTableItemsDetail {
List<GameDetail> gameDetails;
private Long gameId;
private String name;
private String company;
}

View File

@ -13,7 +13,7 @@ import java.util.List;
@NoArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GameTableItems {
public class GameTableItemsSummary {
private Long gameId;
private List<String> gameFilename;
}

View File

@ -1,5 +1,6 @@
package com.cmhi.gds.pojo.entry;
package com.cmhi.gds.pojo.vo;
import com.cmhi.gds.pojo.vo.GameSummary;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

View File

@ -1,10 +1,13 @@
package com.cmhi.gds.service;
import com.cmhi.gds.pojo.vo.GameTableItems;
import com.cmhi.gds.pojo.vo.GameTableItemsDetail;
import com.cmhi.gds.pojo.vo.GameTableItemsSummary;
import java.util.List;
public interface GameDatabaseServiceService {
List<GameTableItems> getGameTableSummaryItems();
List<GameTableItemsSummary> getGameTableSummaryItems();
List<GameTableItemsDetail> getGameTableItems(List<Long> gameIds);
}

View File

@ -0,0 +1,51 @@
package com.cmhi.gds.service;
import com.cmhi.gds.pojo.dto.protocol.base.ProtocolRespDTO;
import com.cmhi.gds.security.protocol.DecryptRequestProtocol;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.http.HttpInputMessage;
import java.io.IOException;
/**
* The interface Protocol security service.
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
public interface ProtocolSecurityService {
/**
* Decrypt protocol string.
*
* @param ciphertext the ciphertext
* @return the string
* @throws JsonProcessingException the json processing exception
*/
String decryptProtocol(String ciphertext) throws JsonProcessingException;
/**
* Decrypt protocol decrypt request protocol.
*
* @param httpInputMessage the http input message
* @return the decrypt request protocol
* @throws IOException the io exception
*/
DecryptRequestProtocol decryptProtocol(HttpInputMessage httpInputMessage) throws IOException;
/**
* Encrypt protocol string string.
*
* @param plainText the plain text
* @param cryptoType the crypto type
* @return the string
*/
String encryptProtocolString(String plainText, int cryptoType);
/**
* Encrypt protocol protocol resp dto.
*
* @param orgProtocol the org protocol
* @param cryptoType the crypto type
* @return the protocol resp dto
*/
ProtocolRespDTO<String> encryptProtocol(Object orgProtocol, int cryptoType);
}

View File

@ -1,14 +1,15 @@
package com.cmhi.gds.service.impl;
import com.cmhi.gds.manager.GameDatabaseServiceManager;
import com.cmhi.gds.pojo.entry.GameSummary;
import com.cmhi.gds.pojo.entry.GameTableSummary;
import com.cmhi.gds.pojo.vo.GameTableItems;
import com.cmhi.gds.pojo.vo.GameSummary;
import com.cmhi.gds.pojo.vo.GameTableItemsDetail;
import com.cmhi.gds.pojo.vo.GameTableItemsSummary;
import com.cmhi.gds.pojo.vo.GameTableSummary;
import com.cmhi.gds.service.GameDatabaseServiceService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -21,14 +22,14 @@ public class GameDatabaseServiceServiceImpl implements GameDatabaseServiceServic
@Override
public List<GameTableItems> getGameTableSummaryItems() {
List<GameTableItems> items = new ArrayList<>();
public List<GameTableItemsSummary> getGameTableSummaryItems() {
List<GameTableItemsSummary> items = new ArrayList<>();
List<GameTableSummary> gs = gameDatabaseServiceManager.getGameTableSummary();
if (!gs.isEmpty()) {
for (GameTableSummary v : gs) {
GameTableItems item = GameTableItems.builder()
GameTableItemsSummary item = GameTableItemsSummary.builder()
.gameId(v.getId())
.build();
@ -46,4 +47,9 @@ public class GameDatabaseServiceServiceImpl implements GameDatabaseServiceServic
}
return items;
}
@Override
public List<GameTableItemsDetail> getGameTableItems(List<Long> gameIds) {
return gameDatabaseServiceManager.getGameTableDetails(gameIds);
}
}

View File

@ -0,0 +1,221 @@
package com.cmhi.gds.service.impl;
import com.cmhi.gds.common.ConstValue;
import com.cmhi.gds.common.ErrorCode;
import com.cmhi.gds.pojo.dto.protocol.base.ProtocolRespDTO;
import com.cmhi.gds.common.GlobalConfigure;
import com.cmhi.gds.common.ProtoCryptoType;
import com.cmhi.gds.common.SecurityConfigValue;
import com.cmhi.gds.exception.ControllerRequestTimeoutException;
import com.cmhi.gds.exception.SecurityProtocolException;
import com.cmhi.gds.pojo.dto.protocol.base.ProtocolReqDTO;
import com.cmhi.gds.security.arithmetic.CryptoHelper;
import com.cmhi.gds.security.protocol.DecryptRequestProtocol;
import com.cmhi.gds.service.ProtocolSecurityService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
/**
* The type Protocol security service.
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
@Service
@Slf4j
public class ProtocolSecurityServiceImpl implements ProtocolSecurityService {
/**
* The Object mapper.
*/
@Resource
private ObjectMapper objectMapper;
/**
* Decrypt protocol string.
*
* @param ciphertext the ciphertext
* @return the string
* @throws JsonProcessingException the json processing exception
*/
@Override
public String decryptProtocol(String ciphertext) throws JsonProcessingException {
JsonNode objRoot = objectMapper.readTree(ciphertext);
// 判断协议请求是否超时
if(GlobalConfigure.CHECK_PROTO_REQUEST_TIMEOUT) {
long timeStamp = objRoot.path("timeStamp").asLong();
long current = System.currentTimeMillis();
long diff = current - timeStamp;
if(diff > GlobalConfigure.REQUEST_TIMEOUT_MS) {
String errMsg = String.format("Request times %d, current times %d, timeout configure %d ms, timeout %d",
timeStamp, current, GlobalConfigure.REQUEST_TIMEOUT_MS, diff);
throw new ControllerRequestTimeoutException(ErrorCode.ERR_REQTIMEOUT, errMsg);
}
}
int cryptoType = objRoot.path("cryptoType").asInt();
// 协议未加密
if (cryptoType == ProtoCryptoType.CRYPTO_NONE.getCode()) {
return ciphertext;
}
if (cryptoType > ProtoCryptoType.CRYPTO_AES256.getCode() || cryptoType < ProtoCryptoType.CRYPTO_NONE.getCode()) {
throw new SecurityProtocolException(ErrorCode.ERR_PARAMS, "cryptoType 字段取值为 [0, 4]");
}
// 反序列化为对象处理
ProtocolReqDTO<String> proReq = objectMapper
.readValue(ciphertext, new TypeReference<ProtocolReqDTO<String>>() {
});
// 首先对加密内容进行base64解码
byte[] base64Decode = CryptoHelper.base64Decryption(proReq.getMsgContent());
// 解密后的内容
byte[] decryptContent;
// 加密类型为base64直接返回处理结果
if (proReq.getCryptoType() == ProtoCryptoType.CRYPTO_BASE64.getCode()) {
decryptContent = base64Decode;
} else if (proReq.getCryptoType() == ProtoCryptoType.CRYPTO_AES128.getCode()) {
try {
decryptContent = CryptoHelper.aes128Decryption(base64Decode, SecurityConfigValue.AES_KEY);
} catch (Exception e) {
log.error("AES128 decode message error: {}", base64Decode);
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_AES128);
}
} else if (proReq.getCryptoType() == ProtoCryptoType.CRYPTO_AES256.getCode()) {
try {
decryptContent = CryptoHelper.aes256Decryption(base64Decode, SecurityConfigValue.AES_KEY);
} catch (Exception e) {
log.error("AES256 decode message error: {}", base64Decode);
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_AES256);
}
} else if (proReq.getCryptoType() == ProtoCryptoType.CRYPTO_DES.getCode()) {
try {
decryptContent = CryptoHelper.desDecryption(base64Decode, SecurityConfigValue.DES_KEY);
} catch (Exception e) {
log.error("DES decode message error: {}", base64Decode);
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_3DES);
}
} else {
log.error("Unknown protocol security type: {}, {}", proReq.getCryptoType(), ciphertext);
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_UNKNOWN);
}
// 字节数组转换为字符串
String decodeMsg = new String(decryptContent, StandardCharsets.UTF_8);
return ciphertext.replace("\"" + proReq.getMsgContent() + "\"", decodeMsg);
}
/**
* Decrypt protocol decrypt request protocol.
*
* @param httpInputMessage the http input message
* @return the decrypt request protocol
* @throws IOException the io exception
*/
@Override
public DecryptRequestProtocol decryptProtocol(HttpInputMessage httpInputMessage) throws IOException {
// 提取协议中的JSON字符串
String reqMessage = IOUtils.toString(httpInputMessage.getBody(), String.valueOf(StandardCharsets.UTF_8));
return new DecryptRequestProtocol(httpInputMessage, decryptProtocol(reqMessage));
}
/**
* Encrypt protocol string string.
*
* @param plainText the plain text
* @param cryptoType the crypto type
* @return the string
*/
@Override
public String encryptProtocolString(String plainText, int cryptoType) {
String cipherText;
if (cryptoType == ProtoCryptoType.CRYPTO_BASE64.getCode()) {
cipherText = CryptoHelper.base64Encryption(plainText.getBytes(StandardCharsets.UTF_8));
} else if (cryptoType == ProtoCryptoType.CRYPTO_AES128.getCode()) {
try {
byte[] encode = CryptoHelper.aes128Encryption(plainText.getBytes(StandardCharsets.UTF_8),
SecurityConfigValue.AES_KEY);
cipherText = CryptoHelper.base64Encryption(encode);
} catch (Exception e) {
log.error("AES128 encode message error: {}", plainText);
throw new SecurityProtocolException(ErrorCode.ERR_ENCRYPT_AES128);
}
} else if (cryptoType == ProtoCryptoType.CRYPTO_AES256.getCode()) {
try {
byte[] encode = CryptoHelper.aes256Encryption(plainText.getBytes(StandardCharsets.UTF_8),
SecurityConfigValue.AES_KEY);
cipherText = CryptoHelper.base64Encryption(encode);
} catch (Exception e) {
log.error("AES256 encode message error: {}", plainText);
throw new SecurityProtocolException(ErrorCode.ERR_ENCRYPT_AES256);
}
} else if (cryptoType == ProtoCryptoType.CRYPTO_DES.getCode()) {
try {
byte[] encode = CryptoHelper.desEncryption(plainText.getBytes(StandardCharsets.UTF_8),
SecurityConfigValue.DES_KEY);
cipherText = CryptoHelper.base64Encryption(encode);
} catch (Exception e) {
log.error("DES encode message error: {}", plainText);
throw new SecurityProtocolException(ErrorCode.ERR_ENCRYPT_3DES);
}
} else {
log.error("Unknown protocol security type: {}, {}", cryptoType, plainText);
throw new SecurityProtocolException(ErrorCode.ERR_ENCRYPT_UNKNOWN);
}
return cipherText;
}
/**
* Encrypt protocol protocol resp dto.
*
* @param orgProtocol the org protocol
* @param cryptoType the crypto type
* @return the protocol resp dto
*/
@Override
public ProtocolRespDTO<String> encryptProtocol(Object orgProtocol, int cryptoType) {
ProtocolRespDTO<String> cryptoObject = new ProtocolRespDTO<>();
cryptoObject.setVer(ConstValue.Protocol.VERSION);
cryptoObject.setCryptoType(SecurityConfigValue.SECURITY_PROTOCOL_TYPE);
cryptoObject.setTimeStamp(System.currentTimeMillis());
String msgContentJsonString;
try {
Method getMsgMethod = orgProtocol.getClass().getMethod("getMsgContent");
Method getCode = orgProtocol.getClass().getMethod("getCode");
msgContentJsonString = new ObjectMapper().writeValueAsString(getMsgMethod.invoke(orgProtocol));
cryptoObject.setCode((Integer) getCode.invoke(orgProtocol));
} catch (Exception e) {
log.error("Json encode message error: {}", orgProtocol);
throw new SecurityProtocolException(ErrorCode.ERR_SYSTEMEXCEPTION);
}
cryptoObject.setMsgContent(encryptProtocolString(msgContentJsonString, cryptoType));
return cryptoObject;
}
}

View File

@ -11,6 +11,7 @@ import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* The type Valid custom base enum.
@ -57,7 +58,7 @@ public class ValidBaseEnumImpl implements ConstraintValidator<ValidBaseEnum, Int
}
List<Integer> enumValues = Arrays.stream(enumClass.getEnumConstants())
.map(BaseEnum::getValue).toList();
.map(BaseEnum::getValue).collect(Collectors.toList());
String errMsg = this.message + " 字段 " +
((ConstraintValidatorContextImpl) ctx).getConstraintViolationCreationContexts()

View File

@ -7,20 +7,42 @@
<result column="company" property="company"/>
</resultMap>
<resultMap id="game_table_summary" type="com.cmhi.gds.pojo.entry.GameTableSummary">
<resultMap id="game_table_summary" type="com.cmhi.gds.pojo.vo.GameTableSummary">
<id column="id" property="id"/>
<collection property="gameFilename" ofType="com.cmhi.gds.pojo.entry.GameSummary">
<collection property="gameFilename" ofType="com.cmhi.gds.pojo.vo.GameSummary">
<result column="id" property="id"/>
<result column="filename" property="filename"/>
</collection>
</resultMap>
<resultMap id="game_table_detail" type="com.cmhi.gds.pojo.vo.GameTableItemsDetail">
<id column="id" property="gameId"/>
<id column="name" property="name"/>
<id column="company" property="company"/>
<collection property="gameDetails" ofType="com.cmhi.gds.pojo.vo.GameDetail">
<result column="id" property="gameInfoId"/>
<result column="filename" property="filename"/>
<result column="version" property="version"/>
<result column="md5sum" property="md5sum"/>
</collection>
</resultMap>
<select id="selectAll" resultMap="game_tables">
SELECT *
FROM game_tables
</select>
<select id="selectAllGameSummary" resultMap="game_table_summary">
SELECT t.id, i.filename FROM game_tables t LEFT JOIN game_info i on t.id = i.gameId;
SELECT t.id, i.filename
FROM game_tables t
LEFT JOIN game_info i on t.id = i.gameId
</select>
<select id="selectAllGameDetailById" resultMap="game_table_detail">
SELECT t.id, t.company, t.name, i.filename, i.version, i.md5sum FROM game_tables t LEFT JOIN game_info i on t.id = i.gameId
WHERE i.id IN
<foreach collection="idList" item="id" index="index" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
</mapper>