背景
一点点补充之前没有考虑到的细节
Validation
自定义参数注入 会导致 Validation 失效
获得到对象后 手动调用 validate(obj);
如下 validate方法
List
上次写的逻辑 对简单参数做了处理
但是 如果前端传递的是List就无法处理了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
@PostMapping("/jgzhyxjsz") public R jgzhyxjsz(List<JgzhyxjszDTO> orders){ return R.data(merchantMngmtService.jgzhyxjsz(orders)); }
|
后台如果不想用 @RequestBody 并且封装一个对象去接收的话
而是这样直接就能获取到 那就必须实现一个 List 的自定义参数转换器
1 2 3 4 5 6 7 8 9 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
| @Slf4j @Component public class HandlerArrayResolver implements HandlerMethodArgumentResolver { @Autowired private Validator validator; @Override public boolean supportsParameter(MethodParameter parameter) { return Collection.class.isAssignableFrom(parameter.getParameterType()); }
@Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container, NativeWebRequest nativeWebRequest, WebDataBinderFactory factory) throws Exception { ContentCachingRequestWrapper request = nativeWebRequest.getNativeRequest(ContentCachingRequestWrapper.class); Object result = null; ParameterizedType genericSuperclass = (ParameterizedType) parameter.getMethod().getGenericParameterTypes()[parameter.getParameterIndex()]; Type type = genericSuperclass.getActualTypeArguments()[0]; String contentType = request.getHeader(HttpHeaders.CONTENT_TYPE); if(request.getBodySize() > 0 && (request.isRewiteBody() || contentType == null || contentType.startsWith(MediaType.APPLICATION_JSON_VALUE))) { String queryBody = request.getQueryBody(); try { if(queryBody.strip().startsWith("[")) { result = JSONObject.parseArray(queryBody,Class.forName(type.getTypeName())); } else if(queryBody.indexOf("\"" + parameter.getParameterName() + "\"") != -1) { String tempStr = JSONObject.parseObject(queryBody).getString(parameter.getParameterName()); result = JSONObject.parseArray(tempStr,Class.forName(type.getTypeName())); } }catch (Exception e) { log.error("参数注入增强-JSON转换失败"); } } return validate(parameter,result); } private Object validate(MethodParameter parameter,Object obj) { if(parameter.getParameterAnnotation(Validated.class) == null && parameter.getParameterAnnotation(Valid.class) == null) return obj; if(obj == null) throw new Exception("参数不能为null", 500); Set<ConstraintViolation<Object>> validateResult = validator.validate(obj); if(validateResult.size() > 0) throw new MysdException(validateResult.iterator().next().getPropertyPath() +":"+ validateResult.iterator().next().getMessage(), 500); return obj; } }
|
参数没有放在QueryBody 中
之前考虑的都是 参数放到QueryBody 如果对方把请求参数写在 QueryParam中
1 2 3 4 5 6 7 8 9 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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| @Slf4j @Order(Ordered.HIGHEST_PRECEDENCE + 1) @Component public class TraceFilter extends ActionFilter {
@Override public void filter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { Long startTime = System.nanoTime(); String contentType = request.getContentType(); log.info("QueryStart_Url(" + request.getRequestURI() + ")_Method("+request.getMethod()+")_Type("+getContentType(contentType)+")_Ip("+getIpAddress(request)+")"+getDevInfo(request.getHeader(HttpHeaders.USER_AGENT))); ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request); log.info("QueryString:" + requestWrapper.getQueryString()); log.info("QueryParameter:" + (requestWrapper.getParameterMap().size() !=0 ? JSON.toJSONString(requestWrapper.getParameterMap()):"")); if (requestWrapper.hasFile() && requestWrapper.getBodySize() != 0) { log.info("QueryBody: 内容是个文件"); } else { String queryBody = requestWrapper.getQueryBody(); String fmqb = queryBody.replaceAll("\\s+", " "); log.info("QueryBody:" + fmqb); if(HttpMethod.GET.matches(request.getMethod()) && requestWrapper.getBodySize() != 0) { queryBody = URLDecoder.decode(queryBody, "UTF-8"); } if(queryBody != null && queryBody.length() > 3 && queryBody.length() < 999) { if((contentType == null || contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) && fmqb.indexOf("[") == -1 ) { JSONObject json = JSONObject.parseObject(queryBody); for(String key : json.keySet()) { String value = json.getString(key); if(StringUtils.isNotEmpty(value) && !value.startsWith("{") && !value.startsWith("[")) requestWrapper.put(key, value); } } if(contentType == null || contentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { String[] params = queryBody.split("&"); for(String param : params) { String[] par = param.split("="); if(par.length != 2) break; requestWrapper.put(par[0], par[1]); } } } if((requestWrapper.getBodySize() == 0 || HttpMethod.GET.matches(request.getMethod())) && (contentType == null || contentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED_VALUE) || contentType.startsWith(MediaType.MULTIPART_FORM_DATA_VALUE) || contentType.startsWith(MediaType.APPLICATION_JSON_VALUE))) { Map<String,String> map = requestWrapper.getParameterMapEx(); if(!map.isEmpty()) { String mapJson = JSON.toJSONString(map) .replaceAll("\"\\{","{") .replaceAll("\\}\"", "}") .replaceAll("\"\\[","[") .replaceAll("\\]\"", "]") .replaceAll("\\\\\"", "\""); requestWrapper.rewriteBody(mapJson); } } } boolean isMeHook = false; ResponseWrapper proxyResponse; if (response instanceof ResponseWrapper) proxyResponse = (ResponseWrapper) response; else { proxyResponse = new ResponseWrapper(response); isMeHook = true; } chain.doFilter(requestWrapper, proxyResponse); if(response != null && (response.getContentType() == null || response.getContentType().startsWith(MediaType.APPLICATION_JSON_VALUE))) log.info("ResponseBody Secret({}) Detail({})", response instanceof CryptoHttpServletResponse, new String(proxyResponse.getContent())); else log.info("ResponseBody Detail({})", "内容未知 type:" + response.getContentType()); Long elapsedTime = DateUtil.nanosToMillis(DateUtil.spendNt(startTime)); log.info("QueryEnd-Url:" + request.getRequestURI() + " elapsedTime(" + elapsedTime + ")"); if(isMeHook) proxyResponse.finish(); }
public static String getContentType(String contentType) { if(StringUtils.isEmpty(contentType)) return "NONE"; if(contentType.indexOf(";") != -1) contentType = contentType.split(";")[0]; if(contentType.indexOf("/") != -1) contentType = contentType.split("/")[1]; return contentType; } public static String getDevInfo(String agent) { ... } public static String getIpAddress(HttpServletRequest request) { ... } }
|
手动把 queryString的参数放到 requestBody 中去
总结
很多人会搞不明白 content-type 的区别
明明说了 用 JSON 请求 参数却放在 param 中
或者需要放在 param 中的参数 放到 body 中 或者参数放到 url 中
如果后端不区分这些 不论 param url body 全部都处理 都可以自由接收
那将极大的降低对接口的工作量
只是有太多情况需要考虑 一点点完善吧~