SpringMVC中HttpRequestMethodNotSupportedException时返回中文乱码分析解决

版权声明:转载必须注明本文转自严振杰的博客:http://blog.yanzhenjie.com

最近写服务器接口时遇到一个令我辗转不眠的问题,为了统一解决RestController的全局异常,包括自定义异常和SpringMVC底层抛出来的异常,我用了@ControllerAdvice来拦截异常,出现的问题是:拦截到自定义异常和MissingServletRequestParameterException返回数据没有问题,但是拦截HttpRequestMethodNotSupportedException时返回带中文的JSON时,客户端接受到时乱码。

其实SpringMVC中处理我的需求的方案不少,在我的方案中遇到的这个问题很怪异,当然也可以秒秒钟用很多种办法解决,但是了解我的人就知道,在技术上这种情况我时绝对不能忍的,我本着打破砂锅问到底的精神,还是跟踪了一下源码。

我的代码

轻描淡写的解释一下,在一个类上加上@ControllerAdvice注解表示增强控制器,再加上@RestController注解表示方法返回的内容是ReponseBody,在这个类内部的方法上加上@ExceptionHandler注解表示扑捉什么异常。

:以上几个注解的解释仅限于此用法中,比如@RestController在控制器中还有别的作用和释义,@ControllerAdvice注解的类内部还可以用@InitBinder@ModelAttribute做其他事情等。

@ControllerAdvice
@RestController
public class AppControlAdvice {

    @ExceptionHandler(BaseException.class)
    public String missingParamHandle(request, response, BaseException e) {
        return handleException(request, response, e);
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public String missingParamHandle(request, response, MissingServletRequestParameterException e) {
        return handleException(request, response, new ClientException("缺少必要的参数"));
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public String methodNotSupportHandle(request, response, HttpRequestMethodNotSupportedException e) {
        return handleException(request, response, new ClientException("不支持的请求方法"));
    }

    public String handleException(request, response, Throwable ex) {
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        ...; // 组织数据并返回统一的JSON。
    }
}

:在@ExceptionHandler中给Response设置在@RequestMapping中指定的属性是无效的,不要问为什么,看完文章你就知道了。

代码解释:

  • BaseException:自定义异常基类。
  • MissingServletRequestParameterException:Query中缺少必要的参数。
  • HttpRequestMethodNotSupportedException:客户端使用的请求方法不被该接口支持。
  • handleException():统一处理错误,并根据错误类型返回JSON字符串。

为了读者方便阅读本文,我们约定一下,抛出MissingServletRequestParameterException异常时称为X接口抛错,抛出HttpRequestMethodNotSupportedException时称为O接口抛错。

关于@ControllerAdvice@ExceptionHandler的用法不再赘述,Google可以搜出来一大票详解的文章,这里出现的问题是扑捉到BaseExceptionX接口抛错时返回JSON后中文不会乱码,O接口抛错时返回的中文居然乱码了,上面可以清晰的看到我给Response设置了Content-Typeutf-8,在web.xml中也指定了编码过滤器使用utf-8

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <async-supported>true</async-supported>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

所以我很确定我返回的字符串是utf-8编码的,于是我用浏览器打开了这个接口,但是我看到浏览器接受到的Content-Type却是text/html;charset=iso-8859-1

Response

问题分析

既然我们设置了响应头的Content-Typeapplication/json;charset=utf-8,但是返回给客户端时居然变了,很显然这是SpringMVC内部帮我们改了,于是我想到在拦截器内拦截所有接口的请求方法,判断客户端的请求方法是否被这个接口支持,如果不支持我直接抛出一个自定义异常,这样不就解决了吗?

定义注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SupportMethod {
    RequestMethod[] value();
}

在接口上添加注解:

@RestController
@RequestMapping("/xxx")
public class XXXController {

    @SupportMethod(RequestMethod.POST);
    @RequestMapping(
            value = "/add",
            method = RequestMethod.POST)
    public String add() {
        ...;
    }
}

拦截器拦截:

public class AppInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(request, response, Object handler) throws Exception {
        if (handler != null && handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            SupportMethod supportMethod = handlerMethod.getMethodAnnotation(SupportMethod.class);
            if(method != null) {
                // 拿到客户端请求方法:
                String inMethod = RequestMethodrequest.getMethod();
                RequestMethod clientMethod = RequestMethod.valueOf(inMethod);

                // 接口指定的请求方法:
                List<RequestMethod> methodList = Arrays.asList(supportMethod.value());

                // 判断是否支持:
                if(!methodList.contains(clientMethod)) {
                    throw new ClientException("不支持的请求方法");
                }
            }
        }
        return true;
    }

理论上这段代码是没有问题的,一般情况时,我们拦截登录时就可以这样做,是完全没毛病的。

But,很快我就被啪啪打脸了,O接口抛错前并没有走拦截器,也就是说DispatcherServlet是先判断的请求方法,然后才走到拦截器,于是我放弃这个方案。

介于此我不得不看一下源码来一探究竟了。

排查原因

打开DispatcherServlet后发现内部提供了一个方法,只要我们重写这个方法就可以统一处理异常:

protected ModelAndView processHandlerException(request, response, Object handler, Exception ex);

很惭愧,要是不看源码我之前确实不知道这个方法,这算是其中一个解决方案,但这不是我的根本目的。

根据上面的分析,我要先找到时哪里修改我在Response中设置的Content-Type请求,从DispatcherServlet分发请求的方法开始debug走起:

protected void doDispatch(request, response) throws Exception {
    try {
        Exception exception = null;
        ...;
A.      mappedHandler = getHandler(request);
        ...;
B.      HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
C.      mv = ha.handle(request, response, mappedHandler.getHandler());
        ...;
D.      applyDefaultViewName(request, mv);
E.      mappedHandler.applyPostHandle(request, response, mv);
    } catch (Exception ex) {
        exception = ex;
    }
F.  processDispatchResult(..., exception);
}

这里省略了一部分代码,剩下的是主要的代码,也是可能出现问题的代码。为了方便读者结合博客阅读代码,我给代码加上了伪行号。

我先在A处代码(获取RequestHandler)打上了断点,分别扑捉X接口抛错和O接口抛错并观察两个异常的时候,代码都是如何走的。实验结果发现:X接口抛错时在执行C(执行Handler)处代码时抛出异常,O接口抛错时在执行A处代码(获取RequestHandler)时抛出异常,那么唯一的区别就是X接口抛错时执行了B处代码(获取Handler的属性)处代码,这里望文生义,getHandlerAdapter的意思不就是拿到Handler的适配器,也就是Controller中方法的@RequestMapping等相关属性了。

于是我猜测是不是这里设置的ResponseContent-Type是无效的,还是会被Handler@RequestMapping覆盖了。然后我又做了个测试,把A接口抛错时返回数据的Conent-Type中的编码改成iso-8859-1看看效果:

@RequestMapping(
    value = "/xxx",
    method = {RequestMethod.GET},
    produces = "application/json;charset=iso-8859-1")

果不其然的印证了我的猜想,客户端果然乱码了,也就是说我返回的数据是utf-8编码的,但是我却告诉客户端我的数据是ios-8859-1的,也就时说在文章开头的这个方法中设置的Content-Type是无效的:

public String handleException(request, response, Throwable ex) {
    response.setHeader("Content-Type", "application/json;charset=UTF-8");
    ...; // 组织数据并返回统一的JSON。
}

特别声明:在@ExceptionHandler中给Response设置在@RequestMapping中指定的属性是无效的。

原因印证

如果上面的测试不够具有说服力,那么下面我带读者们来跟踪下代码。

还是刚才的A处代码(获取RequestHandler)断点,分别扑捉A接口抛错和B接口抛错并观察两个异常的时候,各个对象有什么不同,因为必定是某个对象的某个属性影响了结果。实验结果发现,A接口抛错在走完A处代码(获取RequestHandler)后,RequestAttribute多了如下的属性:

org.springframework.web.servlet.HandlerMapping.producibleMediaTypes: application/json;charset=utf-8

B接口抛错却没有这个属性,我猜想在抛出HttpRequestMethodNotSupportedException异常时Request少了上述属性,这个属性就是为了保存接口@RequestMapping注解的produces属性。那我们一步步跟踪一下我们猜的对不对:

第一步,哪里添加的属性

先从DispatcherServlet#getHandler()下手(大概是940行代码处),:

mappedHandler = getHandler(processedRequest);

跟着代码来到了RequestMappingInfoHandlerMapping#handleMatch()(大概是117行左右),发现了玄机:

if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
    Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
    request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
}

果然是这里添加了接口的属性到Request的属性中,但是这还是不能够证明它影响了返回结果啊。

第二步,哪里验证了属性

这里要麻烦读者朋友回到上面标有伪行号ABCDE那里看看代码,其中有一行F:processDispatchResult(..., exception);,这里是处理了当前请求的结果,无论异常还是正常。

然后跟着processDispatchResult()来到了AbstractMessageConverterMethodProcessor#getProducibleMediaTypes()(大概是304行):

Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
if (!CollectionUtils.isEmpty(mediaTypes)) {
    return new ArrayList<MediaType>(mediaTypes);
}

这下就完全印证了我的猜想,望文生义,getProducibleMediaTypes()就是获取返回ResponseBodyproduces

结论@ControllerAdvice@ExceptionHandler配合使用时,SpringMvc覆盖了我们设置的ResponseContent-Type

解决方案

  1. SpringMVC提交PR,优化这个问题。
  2. 在进入Controller的方法之前SpringMVC抛出的HttpRequestMethodNotSupportedException异常处理返回数据时不要使用中文。
  3. 在扑捉到HttpRequestMethodNotSupportedException异常时自己给Request添加HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE属性,代码如下:
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public String methodNotSupportHandle(request, response, HttpRequestMethodNotSupportedException e) {
    Set<MediaType> mediaTypeSet = new HashSet<>();
    MediaType mediaType = new MediaType("application", "json", Charset.forName("utf-8"));
    mediaTypeSet.add(mediaType);
    request.setAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypeSet);
    return handleException(request, response, new ClientException("不支持的请求方法"));
}

SpringMVC提交PR是我后面要做的事,现在工作生活都比较忙,没时间看的更深入更理解,所以不敢擅自提交PR。


版权声明:转载必须注明本文转自严振杰的博客:http://blog.yanzhenjie.com

发布了51 篇原创文章 · 获赞 1020 · 访问量 159万+
展开阅读全文

org.springframework.web.HttpRequestMethodNotSupportedException: Request method

09-16

jap代码: <a href="/manager/message/{2}.html"><span>全部会员</span></a> <a href="/manager/message/{1}.html"><span>全部研发会员</span></a> <a href="/manager/message/{0}.html"><span>全部企业会员</span></a> controller代码: @RequestMapping(value = "/manager/message/{type}", method = RequestMethod.POST) public String selectUserName(Model m, @PathVariable("type") String type) { m.addAttribute("name", messageService.getUserName(type)); return "manager/message/add"; } service代码: public String getUserName(String type); 实现service代码 @Transactional(readOnly = true) public String getUserName(String type) { Query query ; if("2".equals(type)){ query = userDao.createQuery("from UsersEntity c where c.userType = 0"); }else{ query = userDao.createQuery("from UsersEntity c where c.userType = 0 and c.type = ?",type); } List<UsersEntity> ls = query.list(); List userNames = Lists.newArrayList(); for (int i = 0; i < ls.size(); i++) { UsersEntity entity = ls.get(i); UserVO vo = new UserVO(); DozerBeanMapperSingletonWrapper.getInstance().map(entity, vo); userNames.add(vo.getUserName()); } String userName = userNames.toString(); String name = userName.substring(1, userName.length()-1); return name; } 抛出的异常: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodResolver.resolveHandlerMethod(AnnotationMethodHandlerAdapter.java:623) [org.springframework.web.servlet-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:421) [org.springframework.web.servlet-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414) [org.springframework.web.servlet-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790) [org.springframework.web.servlet-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719) [org.springframework.web.servlet-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644) [org.springframework.web.servlet-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549) [org.springframework.web.servlet-3.0.5.RELEASE.jar:3.0.5.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) [servlet-api.jar:na] at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) [servlet-api.jar:na] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304) [catalina.jar:7.0.12] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.12] at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:157) [javamelody-1.27.0.jar:na] at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:131) [javamelody-1.27.0.jar:na] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.12] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.12] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) [org.springframework.web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) [org.springframework.web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.12] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.12] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:368) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:99) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:119) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:177) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.captcha.JcaptchaAuthenticationFilter.doFilter(JcaptchaAuthenticationFilter.java:98) [spring-security-captcha-3.0.2.jar:na] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:169) [spring-security-web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237) [org.springframework.web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167) [org.springframework.web-3.0.5.RELEASE.jar:3.0.5.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.12] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.12] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240) [catalina.jar:7.0.12] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164) [catalina.jar:7.0.12] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462) [catalina.jar:7.0.12] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) [catalina.jar:7.0.12] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) [catalina.jar:7.0.12] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562) [catalina.jar:7.0.12] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) [catalina.jar:7.0.12] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395) [catalina.jar:7.0.12] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250) [tomcat-coyote.jar:7.0.12] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188) [tomcat-coyote.jar:7.0.12] at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302) [tomcat-coyote.jar:7.0.12] at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_13] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_13] at java.lang.Thread.run(Thread.java:619) [na:1.6.0_13] 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 撸撸猫 设计师: 设计师小姐姐

分享到微信朋友圈

×

扫一扫,手机浏览