springMVC-数据自动封装到返回结果类

-》做javaweb的在开发数据接口的时候都会封装一套统一的结果类,把需要返回给前端的数据放到结果类中的数据域,然后在返回给前端。返回的数据结构倒是规范了,但是每次都需要手动的set数据,是不是很麻烦。

如标题所示写一个能把数据自动封装到结果类的小功能:

一、party1

1、首先想到的是aop来实现,自定义一个注解来标识需要自动封装返回值的handler,现实会是这么如意的吗?我们接着往下看。

a)简约的结果类

@Data
@AllArgsConstructor
public class AjaxResult {

    private Integer code;
    private String message;
    private Object data;

    public static AjaxResult success(Object data) {
        return new AjaxResult(HttpStatus.OK.value(), null, data);
    }

    public static AjaxResult fail(String msg) {
        return new AjaxResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg, null);
    }

}

b)自定义注解

@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoResult {
}

c)aop环绕通知

@Component
@Aspect
@Slf4j
public class AutoResultAop {

    @Pointcut("@annotation(cn.fzy.annotation.AutoResult)")
    public void point() {
    }

    @Around(value = "point()")
    public Object around(ProceedingJoinPoint pjd) {
        Object res = null;
        try {
            res = pjd.proceed();
            log.info(res.toString());
        } catch (Throwable e) {
            e.printStackTrace();
        }
        // 包裹成结果类返回
        return AjaxResult.success(res);
    }

}

d)测试的数据接口

@RestController
public class TestController {

    @GetMapping("/hi")
    @AutoResult
    public String sayHi() {
        return "hi";
    }
}

调用该接口测试,报一个强制转换的错,想想也是情理之中的事。

java.lang.ClassCastException: cn.fzy.vo.AjaxResult cannot be cast to java.lang.String

尽然这种方案不得行,那只有另辟蹊径了。思考了一下:controller上加了@ResponseBody会把数据转换为json格式返回给前台,那我们能不能在这里寻找突破口。

二、party2

尽然有了方向在网上查询资料得知,controller的返回值都将由HandlerMethodReturnValueHandler来处理。

#supportsReturnType(MethodParameter returnType)

:返回false将会由下一个HandlerMethodReturnValueHandler来处理,当返回true是会执行下一面方法?。

#handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)

:returnValue即为controller返回的值,对数据的处理逻辑在这个方法实现。

public interface HandlerMethodReturnValueHandler {


	boolean supportsReturnType(MethodParameter returnType);


	void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

}

它的实现类有很多,那么哪一个是返回json格式的呢?最终定位到:RequestResponseBodyMethodProcessor。看看它是怎么重写这两个方法的。

#supportsReturnType做了什么:方法上有@ResponseBody或者类上有@ResponseBody返回true.

#handleReturnValue做了什么:mavContainer.setRequestHandled(true)告诉后面的HandlerMethodReturnValueHandler我已经接手了,不需要后面的HandlerMethodReturnValueHandler了。writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage)把数据的json格式写入response里面返回给前台,这里就不贴源码了,下去你们可以点下去看看。

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {

	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
				returnType.hasMethodAnnotation(ResponseBody.class));
	}

	
	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

}

 

三、party3

怎么实现都知道了,那我们来愉快的添加一个自己的HandlerMethodReturnValueHandler

a)自定义个returnHandler实现HandlerMethodReturnHandler接口,并重写方法

public class AutoResultReturnHandler implements HandlerMethodReturnValueHandler {
    @Override
    public boolean supportsReturnType(MethodParameter methodParameter) {
        return methodParameter.getMethodAnnotation(AutoResult.class) != null
                || methodParameter.getDeclaringClass().getAnnotation(AutoResult.class) != null;
    }

    @Override
    public void handleReturnValue(Object o, MethodParameter methodParameter,
            ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest) {
        modelAndViewContainer.setRequestHandled(true);
        HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);
        response.setContentType("text/json;charset=UTF-8");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
            writer.print(JSON.toJSONString(AjaxResult.success(o)));
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }
}

b)注册自定义的returnHandler

:自定义的returnHandler要放在前面,不然就轮不到你来处理了,花落他家了(RequestResponseBodyMethodProcessor)。

@Configuration
@EnableWebMvc
public class WebMvcConfig implements InitializingBean {
    @Autowired
    RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    @Override
    public void afterPropertiesSet() {
        List<HandlerMethodReturnValueHandler> returnValueHandlers = requestMappingHandlerAdapter
                .getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> list = new ArrayList<>();
        list.add(new AutoResultReturnHandler());//自定义returnHandler
        list.addAll(returnValueHandlers);
        requestMappingHandlerAdapter.setReturnValueHandlers(list);
    }
}

一下试试:

@RestController
public class TestController {

    @GetMapping("/hi")
    @AutoResult
    public String sayHi() {
        return "hi";
    }

    @GetMapping("/bye")
    public String sayBye() {
        return "bye";
    }
}

加上了@AutoResult注解的,调用该接口测试:

没加注解的

最后:如果执行有异常抛出可以在全局异常处理里面封装相同的结果类。

举一反三:

需要对返回数据做加密操作的同理(如果不改变数据类型,第一种aop也能实现)

就这么愉快的结束了!希望对你有所微薄的帮助。

                                                                                             向上的路并不拥挤,到多数人选择了安逸!--it疯子也

发布了23 篇原创文章 · 获赞 41 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/feng_zi_ye/article/details/88626410