diff --git a/sop-example/sop-story/src/test/java/com/gitee/sop/storyweb/SopStoryApplicationTests.java b/sop-example/sop-story/src/test/java/com/gitee/sop/storyweb/SopStoryApplicationTests.java deleted file mode 100644 index 8602a36d..00000000 --- a/sop-example/sop-story/src/test/java/com/gitee/sop/storyweb/SopStoryApplicationTests.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.gitee.sop.storyweb; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SopStoryApplicationTests { - - @Test - public void contextLoads() { - } - -} - diff --git a/sop-index/sop-index-service/pom.xml b/sop-index/sop-index-service/pom.xml index 3cc1a793..ddd25c61 100644 --- a/sop-index/sop-index-service/pom.xml +++ b/sop-index/sop-index-service/pom.xml @@ -23,6 +23,13 @@ sop-index-api 5.0.0-SNAPSHOT + + com.gitee.sop + sop-spring-boot-starter + 5.0.0-SNAPSHOT + + + org.springframework.boot spring-boot-starter @@ -67,6 +74,10 @@ org.apache.commons commons-lang3 + + commons-fileupload + commons-fileupload + org.hibernate diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/FileInfo.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/FileInfo.java deleted file mode 100644 index fd6772ca..00000000 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/FileInfo.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gitee.sop.index.common; - -import lombok.Data; - -/** - * @author 六如 - */ -@Data -public class FileInfo { - - /** - * 文件名,包含后缀,如:aa.jpg - */ - private String filename; - - /** - * 文件内容 - */ - private byte[] content; - -} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/RouteContext.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/RouteContext.java index 8cc20fc1..8fd9b2d3 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/RouteContext.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/RouteContext.java @@ -1,5 +1,6 @@ package com.gitee.sop.index.common; +import com.gitee.sop.index.request.ApiRequestContext; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/controller/IndexController.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/controller/IndexController.java index 21374335..ea4bac79 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/controller/IndexController.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/controller/IndexController.java @@ -1,13 +1,12 @@ package com.gitee.sop.index.controller; -import com.gitee.sop.index.common.ApiRequest; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequest; +import com.gitee.sop.index.request.ApiRequestContext; import com.gitee.sop.index.common.ApiResponse; import com.gitee.sop.index.service.RouteService; import com.gitee.sop.index.util.RequestUtil; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/ExceptionExecutor.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/ExceptionExecutor.java index 82bc68b0..58a0c282 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/ExceptionExecutor.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/ExceptionExecutor.java @@ -1,6 +1,6 @@ package com.gitee.sop.index.exception; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequestContext; import com.gitee.sop.index.common.ApiResponse; /** diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/impl/ExceptionExecutorImpl.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/impl/ExceptionExecutorImpl.java index 3833b176..a74db615 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/impl/ExceptionExecutorImpl.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/impl/ExceptionExecutorImpl.java @@ -1,6 +1,6 @@ package com.gitee.sop.index.exception.impl; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequestContext; import com.gitee.sop.index.common.ApiResponse; import com.gitee.sop.index.exception.ApiException; import com.gitee.sop.index.exception.ExceptionExecutor; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiRequest.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequest.java similarity index 99% rename from sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiRequest.java rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequest.java index b098334c..dc1097ff 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiRequest.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequest.java @@ -1,4 +1,4 @@ -package com.gitee.sop.index.common; +package com.gitee.sop.index.request; import com.alibaba.fastjson2.annotation.JSONField; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiRequestContext.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequestContext.java similarity index 79% rename from sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiRequestContext.java rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequestContext.java index 2bd3078c..c277ef27 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiRequestContext.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequestContext.java @@ -1,5 +1,6 @@ -package com.gitee.sop.index.common; +package com.gitee.sop.index.request; +import com.gitee.sop.support.request.FileData; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -33,5 +34,5 @@ public class ApiRequestContext { /** * 上传文件 */ - private List files; + private UploadContext uploadContext; } diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequestContextFactory.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequestContextFactory.java new file mode 100644 index 00000000..5448358a --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiRequestContextFactory.java @@ -0,0 +1,73 @@ +package com.gitee.sop.index.request; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.gitee.sop.index.common.SopConstants; +import com.gitee.sop.index.util.RequestUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.MediaType; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.UUID; + +/** + * @author 六如 + */ +@Slf4j +public class ApiRequestContextFactory { + + private static final String CONTENT_TYPE = "content-type"; + private static final String JSON_NAME = "json"; + private static final String TEXT_NAME = "text"; + private static final String MULTIPART = "multipart"; + public static final String FORM = "form"; + + public static ApiRequestContext build(HttpServletRequest request) { + String contentType = request.getHeader(CONTENT_TYPE); + if (contentType == null) { + contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE; + } + ApiRequest apiRequest = new ApiRequest(); + String ip = RequestUtil.getIP(request); + byte[] body; + try { + body = IOUtils.toByteArray(request.getInputStream()); + } catch (IOException e) { + log.error("获取请求体失败", e); + body = new byte[0]; + } + JSONObject params = null; + UploadContext uploadContext = null; + String contentTypeStr = contentType.toLowerCase(); + // 如果是json方式提交 + if (StringUtils.containsAny(contentTypeStr, JSON_NAME, TEXT_NAME)) { + apiRequest = JSON.parseObject(body, ApiRequest.class); + } else if (StringUtils.containsIgnoreCase(contentTypeStr, MULTIPART)) { + // 如果是文件上传请求 + RequestUtil.UploadInfo uploadInfo = RequestUtil.getUploadInfo(request); + params = uploadInfo.getApiParam(); + uploadContext = uploadInfo.getUploadContext(); + } else if (StringUtils.containsIgnoreCase(contentTypeStr, FORM)) { + // APPLICATION_FORM_URLENCODED请求 + params = RequestUtil.parseQuerystring(new String(body, SopConstants.CHARSET_UTF8)); + } else { + // get请求,参数跟在url后面 + params = RequestUtil.parseParameterMap(request.getParameterMap()); + } + if (params != null) { + apiRequest = params.toJavaObject(ApiRequest.class); + } + + return ApiRequestContext.builder() + .apiRequest(apiRequest) + .locale(request.getLocale()) + .ip(ip) + .uploadContext(uploadContext) + .traceId(UUID.randomUUID().toString().replace("-", "")) + .build(); + } + +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiUploadContext.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiUploadContext.java new file mode 100644 index 00000000..361ed72b --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/ApiUploadContext.java @@ -0,0 +1,46 @@ +package com.gitee.sop.index.request; + +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 存放上传文件 + * + * @author tanghc + */ +public class ApiUploadContext implements UploadContext { + + /** + * key: 表单name + */ + private Map> fileMap; + private List allFile; + + public ApiUploadContext(Map> map) { + if (map == null) { + map = Collections.emptyMap(); + } + this.fileMap = map; + this.allFile = new ArrayList<>(); + map.values().forEach(list -> this.allFile.addAll(list)); + } + + @Override + public MultipartFile getFile(int index) { + return this.allFile.get(index); + } + + @Override + public List getFile(String name) { + return fileMap.get(name); + } + + @Override + public List getAllFile() { + return this.allFile; + } +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/UploadContext.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/UploadContext.java new file mode 100644 index 00000000..cc1a68ce --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/request/UploadContext.java @@ -0,0 +1,36 @@ +package com.gitee.sop.index.request; + +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 获取上传文件 + * + * @author tanghc + */ +public interface UploadContext { + /** + * 根据索引获取上传文件,从0开始 + * + * @param index + * @return 返回上传文件信息 + */ + MultipartFile getFile(int index); + + /** + * 根据表单名获取上传文件 + * + * @param name + * 表单名称 + * @return 返回上传文件信息 + */ + List getFile(String name); + + /** + * 获取所有的上传文件 + * + * @return 返回所有的上传文件 + */ + List getAllFile(); +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java index d06121db..c6cceaf3 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java @@ -1,6 +1,6 @@ package com.gitee.sop.index.service; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequestContext; import com.gitee.sop.index.common.ApiResponse; /** diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteServiceImpl.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteServiceImpl.java index be01461c..8f847d9c 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteServiceImpl.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteServiceImpl.java @@ -3,15 +3,16 @@ package com.gitee.sop.index.service; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.gitee.sop.index.common.ApiInfoDTO; -import com.gitee.sop.index.common.ApiRequest; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequest; +import com.gitee.sop.index.request.ApiRequestContext; import com.gitee.sop.index.common.ApiResponse; import com.gitee.sop.index.common.AttachmentNames; import com.gitee.sop.index.common.ParamInfoDTO; -import com.gitee.sop.index.common.ParamNames; import com.gitee.sop.index.exception.ExceptionExecutor; +import com.gitee.sop.index.request.UploadContext; import com.gitee.sop.index.service.validate.Validator; import com.gitee.sop.index.util.ClassUtil; +import com.gitee.sop.support.request.FileData; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.rpc.RpcContext; @@ -23,6 +24,7 @@ import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; /** * 接口路由 @@ -69,7 +71,7 @@ public class RouteServiceImpl implements RouteService { apiInfo.getInterfaceClassName(), apiInfo.getMethodName(), buildParamType(paramInfoList), - buildInvokeParam(apiRequest, paramInfoList) + buildInvokeParam(apiRequestContext, paramInfoList) ); if (result instanceof Map) { ((Map) result).remove(CLASS); @@ -98,26 +100,36 @@ public class RouteServiceImpl implements RouteService { .toArray(String[]::new); } - protected Object[] buildInvokeParam(ApiRequest apiRequest, List paramInfoList) { + protected Object[] buildInvokeParam(ApiRequestContext apiRequestContext, List paramInfoList) { if (ObjectUtils.isEmpty(paramInfoList)) { return new Object[0]; } + ApiRequest apiRequest = apiRequestContext.getApiRequest(); String bizContent = apiRequest.getBiz_content(); JSONObject jsonObject = JSON.parseObject(bizContent); List params = new ArrayList<>(); for (ParamInfoDTO paramInfoDTO : paramInfoList) { - if (ClassUtil.isPrimitive(paramInfoDTO.getType())) { - String paramName = paramInfoDTO.getName(); - try { - Object value = jsonObject.getObject(paramName, ClassUtils.forName(paramInfoDTO.getType())); - params.add(value); - jsonObject.remove(paramName); - } catch (ClassNotFoundException e) { - log.error("找不到参数class, paramInfoDTO={}, apiRequest={}", paramInfoDTO, apiRequest, e); - throw new RuntimeException("找不到class:" + paramInfoDTO.getType(), e); + String type = paramInfoDTO.getType(); + // 如果是文件上传 + if (Objects.equals(type, FileData.class.getName())) { + UploadContext uploadContext = apiRequestContext.getUploadContext(); + if (uploadContext == null) { + continue; } } else { - params.add(jsonObject); + if (ClassUtil.isPrimitive(type)) { + String paramName = paramInfoDTO.getName(); + try { + Object value = jsonObject.getObject(paramName, ClassUtils.forName(type)); + params.add(value); + jsonObject.remove(paramName); + } catch (ClassNotFoundException e) { + log.error("找不到参数class, paramInfoDTO={}, apiRequest={}", paramInfoDTO, apiRequest, e); + throw new RuntimeException("找不到class:" + type, e); + } + } else { + params.add(jsonObject); + } } } return params.toArray(new Object[0]); diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/AbstractSigner.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/AbstractSigner.java index 9de2ea62..b5ae5e0f 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/AbstractSigner.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/AbstractSigner.java @@ -1,7 +1,7 @@ package com.gitee.sop.index.service.validate; -import com.gitee.sop.index.common.ApiRequest; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequest; +import com.gitee.sop.index.request.ApiRequestContext; import com.gitee.sop.index.exception.ApiException; import com.gitee.sop.index.message.ErrorEnum; import lombok.extern.slf4j.Slf4j; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/ApiValidator.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/ApiValidator.java index be09d786..b13bff83 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/ApiValidator.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/ApiValidator.java @@ -1,13 +1,14 @@ package com.gitee.sop.index.service.validate; import com.gitee.sop.index.common.ApiInfoDTO; -import com.gitee.sop.index.common.ApiRequest; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequest; +import com.gitee.sop.index.request.ApiRequestContext; import com.gitee.sop.index.common.ParamNames; import com.gitee.sop.index.common.StatusEnum; import com.gitee.sop.index.config.ApiConfig; import com.gitee.sop.index.exception.ApiException; import com.gitee.sop.index.message.ErrorEnum; +import com.gitee.sop.index.request.UploadContext; import com.gitee.sop.index.service.ApiInfoService; import com.gitee.sop.index.service.manager.IpBlacklistManager; import com.gitee.sop.index.service.manager.IsvApiPermissionManager; @@ -47,10 +48,16 @@ public class ApiValidator implements Validator { private final Signer signer = new AlipaySigner(); /** - * 单个文件大小 + * 单个文件内容最大值 */ - @Value("${upload.max-file-size:${spring.servlet.multipart.max-file-size:10MB}}") - private String maxFileSize; + @Value("${upload.one-file-max-size}") + private DataSize oneFileMaxSize; + + /** + * 总文件最大值 + */ + @Value("${upload.total-file-max-size}") + private DataSize maxFileSize; @Resource private ApiConfig apiConfig; @@ -122,6 +129,9 @@ public class ApiValidator implements Validator { public void checkField(ApiRequestContext apiRequestContext) { ApiRequest apiRequest = apiRequestContext.getApiRequest(); + if (apiRequest == null) { + throw new ApiException(ErrorEnum.ISV_INVALID_PARAMETER, apiRequestContext.getLocale()); + } Locale locale = apiRequestContext.getLocale(); if (ObjectUtils.isEmpty(apiRequest.getApp_id())) { throw new ApiException(ErrorEnum.ISV_MISSING_APP_ID, locale); @@ -165,7 +175,27 @@ public class ApiValidator implements Validator { * @param apiRequestContext apiRequestContext */ protected void checkUploadFile(ApiRequestContext apiRequestContext) { - // todo:校验上传文件内容 + // 校验上传文件内容 + UploadContext uploadContext = apiRequestContext.getUploadContext(); + if (uploadContext != null) { + List allFiles = uploadContext.getAllFile(); + if (ObjectUtils.isEmpty(allFiles)) { + return; + } + + for (MultipartFile multipartFile : allFiles) { + checkSingleFileSize(apiRequestContext, multipartFile); + } + + long totalSize = allFiles.stream() + .map(MultipartFile::getSize) + .mapToLong(Long::longValue) + .sum(); + + if (totalSize > maxFileSize.toBytes()) { + throw new ApiException(ErrorEnum.ISV_INVALID_FILE_SIZE, apiRequestContext.getLocale(), totalSize, maxFileSize); + } + } } /** @@ -175,8 +205,9 @@ public class ApiValidator implements Validator { */ private void checkSingleFileSize(ApiRequestContext apiRequestContext, MultipartFile file) { long fileSize = file.getSize(); - if (fileSize > DataSize.parse(maxFileSize).toBytes()) { - throw new ApiException(ErrorEnum.ISV_INVALID_FILE_SIZE, apiRequestContext.getLocale(), fileSize, maxFileSize); + long maxSize = oneFileMaxSize.toBytes(); + if (fileSize > maxSize) { + throw new ApiException(ErrorEnum.ISV_INVALID_FILE_SIZE, apiRequestContext.getLocale(), fileSize, maxSize); } } diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/Signer.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/Signer.java index 79f65edc..3d484ead 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/Signer.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/Signer.java @@ -1,6 +1,6 @@ package com.gitee.sop.index.service.validate; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequestContext; /** * 负责签名校验 diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/Validator.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/Validator.java index 8ab9ca27..8039f7d8 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/Validator.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/Validator.java @@ -1,7 +1,7 @@ package com.gitee.sop.index.service.validate; import com.gitee.sop.index.common.ApiInfoDTO; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequestContext; /** * 校验接口 diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/alipay/AlipaySigner.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/alipay/AlipaySigner.java index c011a49c..a3567302 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/alipay/AlipaySigner.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/alipay/AlipaySigner.java @@ -1,8 +1,8 @@ package com.gitee.sop.index.service.validate.alipay; -import com.gitee.sop.index.common.ApiRequest; -import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.request.ApiRequest; +import com.gitee.sop.index.request.ApiRequestContext; import com.gitee.sop.index.common.ParamNames; import com.gitee.sop.index.exception.ApiException; import com.gitee.sop.index.exception.SignException; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RequestUtil.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RequestUtil.java index fe4ae80f..2e638b18 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RequestUtil.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RequestUtil.java @@ -1,18 +1,40 @@ -// -// Source code recreated from a .class file by IntelliJ IDEA -// (powered by FernFlower decompiler) -// - package com.gitee.sop.index.util; -import javax.servlet.http.HttpServletRequest; -import java.net.InetAddress; -import java.net.UnknownHostException; +import com.alibaba.fastjson2.JSONObject; +import com.gitee.sop.index.common.SopConstants; +import com.gitee.sop.index.request.ApiUploadContext; +import com.gitee.sop.index.request.UploadContext; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; +import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest; +import javax.servlet.http.HttpServletRequest; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.URLDecoder; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j public class RequestUtil { + private static final String UTF8 = "UTF-8"; private static final String IP_UNKNOWN = "unknown"; private static final String IP_LOCAL = "127.0.0.1"; private static final int IP_LEN = 15; + private static final String X_FORWARDED_FOR = "x-forwarded-for"; + private static final String PROXY_CLIENT_IP = "Proxy-Client-IP"; + private static final String PROXY_CLIENT_IP1 = "WL-Proxy-Client-IP"; /** * 获取客户端IP @@ -21,14 +43,14 @@ public class RequestUtil { * @return 返回ip */ public static String getIP(HttpServletRequest request) { - String ipAddress = request.getHeader("x-forwarded-for"); - if (ipAddress == null || ipAddress.length() == 0 || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) { - ipAddress = request.getHeader("Proxy-Client-IP"); + String ipAddress = request.getHeader(X_FORWARDED_FOR); + if (ipAddress == null || ipAddress.isEmpty() || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader(PROXY_CLIENT_IP); } - if (ipAddress == null || ipAddress.length() == 0 || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) { - ipAddress = request.getHeader("WL-Proxy-Client-IP"); + if (ipAddress == null || ipAddress.isEmpty() || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader(PROXY_CLIENT_IP1); } - if (ipAddress == null || ipAddress.length() == 0 || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) { + if (ipAddress == null || ipAddress.isEmpty() || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (IP_LOCAL.equals(ipAddress)) { // 根据网卡取本机配置的IP @@ -50,4 +72,106 @@ public class RequestUtil { } return ipAddress; } + + /** + * 将get类型的参数转换成JSONObject + * + * @param query charset=utf-8&biz_content=xxx + * @return 返回map参数 + */ + public static JSONObject parseQuerystring(String query) { + if (query == null) { + return new JSONObject(); + } + String[] queryList = StringUtils.split(query, '&'); + JSONObject params = new JSONObject(); + for (String param : queryList) { + String[] paramArr = param.split("="); + if (paramArr.length == 2) { + try { + params.put(paramArr[0], URLDecoder.decode(paramArr[1], UTF8)); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } else if (paramArr.length == 1) { + params.put(paramArr[0], ""); + } + } + return params; + } + + public static JSONObject parseParameterMap(Map parameterMap) { + if (parameterMap == null || parameterMap.isEmpty()) { + return new JSONObject(); + } + JSONObject jsonObject = new JSONObject(); + parameterMap.forEach((key, value) -> jsonObject.put(key, value[0])); + return jsonObject; + } + + /** + * 获取上传文件内容 + * + * @param request request + * @return 返回文件内容和表单内容 + */ + public static UploadInfo getUploadInfo(HttpServletRequest request) { + if (request instanceof StandardMultipartHttpServletRequest) { + return getUploadInfo((StandardMultipartHttpServletRequest) request); + } + UploadInfo uploadInfo = new UploadInfo(); + // 创建一个文件上传解析器 + ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); + UploadContext uploadContext = null; + JSONObject uploadParams = new JSONObject(); + try { + List multipartFileList = new ArrayList<>(8); + List fileItems = upload.parseRequest(request); + for (FileItem fileItem : fileItems) { + if (fileItem.isFormField()) { + uploadParams.put(fileItem.getFieldName(), fileItem.getString(SopConstants.UTF8)); + } else { + multipartFileList.add(new CommonsMultipartFile(fileItem)); + } + } + if (!multipartFileList.isEmpty()) { + Map> multipartFileMap = multipartFileList + .stream() + .collect(Collectors.groupingBy(MultipartFile::getName)); + uploadContext = new ApiUploadContext(multipartFileMap); + } + + JSONObject apiParam = parseParameterMap(request.getParameterMap()); + uploadParams.putAll(apiParam); + uploadInfo.setApiParam(uploadParams); + uploadInfo.setUploadContext(uploadContext); + } catch (Exception e) { + log.error("参数解析错误", e); + } + return uploadInfo; + } + + public static UploadInfo getUploadInfo(StandardMultipartHttpServletRequest request) { + UploadInfo uploadInfo = new UploadInfo(); + MultiValueMap multiFileMap = request.getMultiFileMap(); + List multipartFileList = new ArrayList<>(multiFileMap.size()); + for (String key : multiFileMap.keySet()) { + multipartFileList.addAll(multiFileMap.get(key)); + } + Map> multipartFileMap = multipartFileList + .stream() + .collect(Collectors.groupingBy(MultipartFile::getName)); + UploadContext uploadContext = new ApiUploadContext(multipartFileMap); + + JSONObject apiParam = parseParameterMap(request.getParameterMap()); + uploadInfo.setApiParam(apiParam); + uploadInfo.setUploadContext(uploadContext); + return uploadInfo; + } + + @Data + public static class UploadInfo { + private JSONObject apiParam; + private UploadContext uploadContext; + } } diff --git a/sop-index/sop-index-service/src/main/resources/application.properties b/sop-index/sop-index-service/src/main/resources/application.properties index 9d7dd677..53443a16 100644 --- a/sop-index/sop-index-service/src/main/resources/application.properties +++ b/sop-index/sop-index-service/src/main/resources/application.properties @@ -12,7 +12,22 @@ dubbo.protocol.port=-1 # redis://localhost:6379 Cluster config:redis://10.20.153.10:6379?backup=10.20.153.11:6379,10.20.153.12:6379 # ------ dubbo.registry.address=nacos://localhost:8848 +# max payload size, 10MB +# 1KB = 1024 +# 1MB = 1048576 +# 1GB = 1073741824 +# 1TB = 1099511627776 +dubbo.protocol.payload=10485760 +####### file upload config ####### +# one file max size limit, unit:KB/MB +upload.one-file-max-size=1MB +# total files max size limit +upload.total-file-max-size=5MB +# Ensure that this configuration is larger than {upload.one-file-max-size} +spring.servlet.multipart.max-file-size=5MB +# Ensure that this configuration is larger than {upload.total-file-max-size} and {dubbo.protocol.payload} +spring.servlet.multipart.max-request-size=20MB ####### mysql config ####### mysql.host=127.0.0.1:3306 diff --git a/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/config/SopAutoConfiguration.java b/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/config/SopAutoConfiguration.java index 905e207e..87c5548a 100644 --- a/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/config/SopAutoConfiguration.java +++ b/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/config/SopAutoConfiguration.java @@ -10,6 +10,7 @@ import org.apache.dubbo.config.annotation.DubboReference; import org.apache.dubbo.config.annotation.DubboService; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationUtils; @@ -44,8 +45,14 @@ public class SopAutoConfiguration implements InitializingBean { @DubboReference private ApiRegisterService apiRegisterService; + @Value("${open.register.enable:true}") + private boolean enableRegister; + @Override public void afterPropertiesSet() throws Exception { + if (!enableRegister) { + return; + } String appName = environment.getProperty("spring.application.name"); Map beanMap = applicationContext.getBeansWithAnnotation(DubboService.class); for (Object serviceObj : beanMap.values()) { diff --git a/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/request/FileData.java b/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/request/FileData.java new file mode 100644 index 00000000..03e3e3f1 --- /dev/null +++ b/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/request/FileData.java @@ -0,0 +1,34 @@ +package com.gitee.sop.support.request; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author 六如 + */ +@Data +public class FileData implements Serializable { + private static final long serialVersionUID = -7588392091014943373L; + + /** + * 上传文件表单名称 + */ + private String name; + + /** + * 原始文件名称,可能为null + */ + private String originalFilename; + + /** + * 文件的contentType,可能为null + */ + private String contentType; + + /** + * 文件内容 + */ + private byte[] content; + +} diff --git a/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/request/OpenRequest.java b/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/request/OpenRequest.java deleted file mode 100644 index 9b183ced..00000000 --- a/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/request/OpenRequest.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.gitee.sop.support.request; - -import lombok.Data; -import org.springframework.core.GenericTypeResolver; - -import java.io.Serializable; - -/** - * @author 六如 - */ -@Data -public class OpenRequest implements Serializable { - private static final long serialVersionUID = -6703437435180048422L; - - private Class clazz; - - public OpenRequest() { - clazz = (Class) GenericTypeResolver.resolveTypeArgument(getClass(), OpenRequest.class); - } - - /** - * 分配给开发者的应用ID - * - * @mock 2014072300007148 - */ - private String app_id; - - /** - * 接口名称 - * - * @mock alipay.trade.fastpay.refund.query - */ - private String method; - - /** - * 仅支持JSON - * - * @mock json - */ - private String format; - - /** - * 请求使用的编码格式,如utf-8,gbk,gb2312等 - * - * @mock utf-8 - */ - private String charset; - - /** - * 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2 - * - * @mock RSA2 - */ - private String sign_type; - - /** - * 商户请求参数的签名串,详见签名 - */ - private String sign; - - /** - * 发送请求的时间,格式"yyyy-MM-dd HH:mm:ss" - * - * @mock 2014-07-24 03:07:50 - */ - private String timestamp; - - /** - * 调用的接口版本,固定为:1.0 - * - * @mock 1.0 - */ - private String version; - - /** - * 支付宝服务器主动通知商户服务器里指定的页面http/https路径 - * - * @mock http://ww.xx.com/callback - */ - private String notify_url; - - /** - * 授权token,详见应用授权概述 - */ - private String app_auth_token; - - /** - * 请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档 - */ - private String biz_content; - -}