SSM+shiro等Java首页投稿(暂停使用,暂停投稿)

Spring自定义注解实现json参数传递

2016-05-23  本文已影响2744人  OneFish

实现(POST,GET)传参自动转换成Json对象,所有参数为Json格式然后再Base64加密

Spring Request详解:

Spring 的DispatcherServlet 实现了Servlet方法,来处理一次请求

DispatcherServlet主要是执行了两个方法doService(HttpServletRequest request, HttpServletResponse response),doDispatch(HttpServletRequest request, HttpServletResponse response)

在doDispatch方法中

    // Determine handler for the current request.

    mappedHandler = getHandler(processedRequest);

获取当前请求的handler,也就是获取到执行当前request的bean。

HandlerMapping有多个实现,具体的还需自己看下实现

    // Determine handler adapter for the current request.

    HandlerAdapterha = getHandlerAdapter(mappedHandler.getHandler());

获取到当前请求的HandlerAdapter

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    for (HandlerMapping hm : this.handlerMappings) {
        if (logger.isTraceEnabled()) {
            logger.trace(
                    "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        HandlerExecutionChain handler = hm.getHandler(request);
        if (handler != null) {
            return handler;
        }
    }
    return null;
}

获取ha.supports(handler) 返回为true的HandlerAdapter

eg.
如果这个bean实现了HttpRequestHandler接口则返回HttpRequestHandlerAdapter

@Override
public boolean supports(Object handler) {
    return (handler instanceof HttpRequestHandler);
}

如果这个bean实现了Controller接口则返回SimpleControllerHandlerAdapter

@Override
public boolean supports(Object handler) {
    return (handler instanceof Controller);
}

目前常用的方式是通过@Controller、@RequestMapping和Spring配置中添加<context:component-scan/>

此时使用的是RequestMappingHandlerAdapter

RequestMappingHandlerAdapter 主要实现了请求参数的封装处理,返回参数的封装处理,支持注入argumentResolvers、returnValueHandlers、messageConverters等来实现扩展

RequestMappingHandlerAdapter.invokeHandlerMethod.invokeAndHandle.invokeForRequest.getMethodArgumentValues


if (this.argumentResolvers.supportsParameter(parameter)) {
    try {
        args[i] = this.argumentResolvers.resolveArgument(
                parameter, mavContainer, request, this.dataBinderFactory);
        continue;
    }
    catch (Exception ex) {
        if (logger.isDebugEnabled()) {
            logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
        }
        throw ex;
    }
}

首先会调用argumentResolver的supportsParameter判断是否可用,然后再执行resolveArgument方法

SpecialArgumentsResolver,自定义argumentResolver

通过上面我们可以发现,基于自定义注解实现Json的参数传递,需要实现自定的argumentResolver并注入到RequestMappingHandlerAdapter中

  1. 实现自定义Json注解

/**
 * Created by zhaoqi on 2016/5/5.
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Json {

    Class[] types() default java.lang.Object.class;

    String path() default "";
}


  1. spring配置文件增加自定义argumentResolver

注意,如果是注入的argumentResolver,会覆盖默认的argumentResolver。

<!--RequestMappingHandlerAdapter加入自定义ArgumentsResolver-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="synchronizeOnSession" value="true" />
    <property name="argumentResolvers">
        <list>
            <bean class="com.zhaoqi.component.annotation.SpecialArgumentsResolver"/>
        </list>
    </property>
    <property name="messageConverters">
        <list>
            <ref bean="stringConverter" />
            <ref bean="jsonConverter" />
        </list>
    </property>
</bean>

如果不想覆盖默认的argumentResolver,请注入customArgumentResolvers。


// Custom arguments

if(getCustomArgumentResolvers() !=null) {

    resolvers.addAll(getCustomArgumentResolvers());

}
  1. 实现SpecialArgumentsResolver

/**
 * Created by zhaoqi on 2016/5/6.
 */
public class SpecialArgumentsResolver implements HandlerMethodArgumentResolver {
    @Resource
    DotaJsonHttpMessageConverter dotaJsonHttpMessageConverter;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(Json.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        return this.readArguments(webRequest, parameter, parameter.getGenericParameterType());
    }

    private Object readArguments(NativeWebRequest webRequest, MethodParameter parameter, Type genericParameterType) {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
        Object arg =null;
        try {
            // get方式取queryString
            if (servletRequest.getMethod().equals(RequestMappingHandlerAdapter.METHOD_GET)) {
                // base64解码
                String decodedQueryString = new String(Base64Utils.decodeFromString(servletRequest.getQueryString()));
                return JsonUtil.toObject(decodedQueryString, Class.forName(genericParameterType.getTypeName()));
            }
            // Json注解使用dotaJsonHttpMessageConverter读取参数
            arg = dotaJsonHttpMessageConverter.readInternal(Class.forName(genericParameterType.getTypeName()), inputMessage);
            if (null == arg) {
                throw new HttpMessageNotReadableException("Required request body is missing: " +
                        parameter.getMethod().toGenericString());
            }
        } catch (IOException | ClassNotFoundException e) {
            //
        }
        return arg;
    }
}

实际使用

@RequestMapping("/sayHi")
@ResponseBody
public ResponseVo getFeedback(@Json HelloRequest hello){
    ResponseVo responseVo = new ResponseVo();
    responseVo.setMsg("success");
    responseVo.setData(hello.getHello());
    return responseVo;
}

好处

上一篇下一篇

猜你喜欢

热点阅读