RestController 和Controller的区别

返回结果

在SpringMVC中,经常会使用注解 的方式来定义一个控制器。
最常用的控制器注解@Controller,可以在控制器类中写各种业务方法,然后返回数据。
一般数据的返回分成两大种,页面 和 json 格式数据

页面
  1. 直接返回视图(页面的名称)名称
@RequestMapping("/index")
String index(){
	return "index";
}
  1. ModelAndView 对象
  @RequestMapping("/user")
    public ModelAndView user(){
        Map<String,Object>values= new HashMap<>();
        values.put("id",1L);
        values.put("name","test");
        return new ModelAndView("user", values);
    }

返回页面和相应数据。一般配合 Thymeleaf 、 Velocity、FreeMarke使用。spring boot 官方推荐使用 Thymeleaf 。该方式类似早期的jsp页面,将数据渲染后的页面返回前台

json

现在一般应用都是前后分离,所以返回json数据的方式使用更频繁。

我们有两种方式将返回的结果转化为josn:

  1. 使用 @Controller(修饰类) 和@ResponseBody(修饰方法) 两个注解,当然@ResponseBody还可以直接修饰类。
  2. 如果某个控制器类设计初衷就是返回json数据,那么该类可以使用简化方式 @RestCotroller
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller  //控制器注解
@ResponseBody   //返回数据会被解析成json
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}

从上面的源码中可以清晰的看到@RestController = @Controller + @ResponseBody

如何抉择

使用@Controller修饰类,可以根据需要返回各种我们所需的数据(json,ModelAndView,静态页面),而使用RestController修饰类,最后返回结果都会被解析成json字符串,适合所有方法返回值都是json数据

ResponseBody注解解析

为什么使用 ResponseBody注解 可以实现 JavaBen 到 json字符串 的自动转化?????????

springMVC 会根据方法的返回类型、方法注解等,挑选合适的返回结果处理器

【HandlerMethodReturnValueHandlerComposite.java】

	/**
	 * Iterate over registered {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers} and invoke the one that supports it.
	 * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
	 */
	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
		// 获取适合的 返回值处理器
		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
		// 返回值处理
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}
	
	/**
	* 选择合适的处理器
	*/
	@Nullable
	private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
		boolean isAsyncValue = isAsyncReturnValue(value, returnType);
		// 遍历已注册的处理器
		for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
			if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
				continue;
			}
			// 根据supportsReturnType 方法,判断处理器是否可以处理该返回结果
			if (handler.supportsReturnType(returnType)) {
				return handler;
			}
		}
		return null;
	}

在这里插入图片描述

上面提到的返回结果 页面 或者 ModelAndView,分别对应了ViewNameMethodReturnValueHandler 、 ModelAndViewMethodReturnValueHandler

	// ModelAndViewMethodReturnValueHandler # supportsReturnType
	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return ModelAndView.class.isAssignableFrom(returnType.getParameterType());
	}
	
	//ViewNameMethodReturnValueHandler  # supportsReturnType
	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		Class<?> paramType = returnType.getParameterType();
		return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
	}

而我们常用的 ResponseBody 注解对应了 RequestResponseBodyMethodProcessor处理器

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

RequestResponseBodyMethodProcessor 处理器的父类AbstractMessageConverterMethodProcessor,完成了数据转化数据增强处理的操作。

我们知道通过实现 ResponseBodyAdvice 接口,可以对使用 @RequestBody 注解的方法(或类下的所有方法)进行增强操作

for (HttpMessageConverter<?> converter : this.messageConverters) {
	GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
			(GenericHttpMessageConverter<?>) converter : null);

	// 判断消息转化器是否可以应用到 该数据类型
	if (genericConverter != null ?
			((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
			converter.canWrite(valueType, selectedMediaType)) {
		// 增强处理
		body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
				(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
				inputMessage, outputMessage);
		if (body != null) {
			Object theBody = body;
			LogFormatUtils.traceDebug(logger, traceOn ->
					"Writing [" + LogFormatUtils.formatValue(theBody, traceOn) + "]");
			addContentDispositionHeader(inputMessage, outputMessage);
			
			// 内容转化
			if (genericConverter != null) {
				genericConverter.write(body, targetType, selectedMediaType, outputMessage);
			}
			else {
				((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Nothing to write: null body");
			}
		}
		return;
	}
}

在这里插入图片描述
上面的逻辑是根据 数据类型(application/json)

body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
				(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
				inputMessage, outputMessage);

该部分代码 就是实现增强处理功能

if (genericConverter != null) {
	genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
	((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}

该部分实现了消息转化,可以自行查看FastJsonHttpMessageConverter的处理过程

大致过程如下
【FastJsonHttpMessageConverter.java】

@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, 
HttpMessageNotWritableException {

	ByteArrayOutputStream outnew = new ByteArrayOutputStream();
	// 对象转化为JSON字符换并保存到 字节数组流
	int len = JSON.writeJSONString(outnew, //
	         fastJsonConfig.getCharset(), //
	         object, //
	         fastJsonConfig.getSerializeConfig(), //
	         //fastJsonConfig.getSerializeFilters(), //
	         allFilters.toArray(new SerializeFilter[allFilters.size()]),
	         fastJsonConfig.getDateFormat(), //
	         JSON.DEFAULT_GENERATE_FEATURE, //
	         fastJsonConfig.getSerializerFeatures());
	// OutputStream getBody()
	// 将字节数组流中的数据 写入到 ServletOutputStream
	outnew.writeTo(outputMessage.getBody());
}
  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: @RestController和@Controller区别在于@RestController是Spring4之后加入的注解,它的作用相当于@Controller和@ResponseBody的结合体,可以直接返回JSON、XML等内容,而@Controller则需要在方法上添加@ResponseBody注解才能返回JSON等内容。另外,@RestController还可以省略@RequestMapping中的value值,直接使用@RequestMapping("/")即可。 ### 回答2: RestControllerController都是Spring框架中用来处理HTTP请求的注解,但是它们有不同的作用和使用方法。 Controller是一个最基本的注解,用来标识Spring MVC控制器类,它的作用是用来解决请求与响应之间的转接和处理。Controller的方法可以返回一个View(视图),视图包含了将要被呈现给用户的数据和页面模板,然后由ViewResolver来查找并渲染视图。在Controller中可以使用ModelAttribute注解将数据传递给Model,可以使用RequestMapping注解来将请求映射到控制器某个方法上,也可以使用SessionAttributes注解来保存数据到Session中。Controller注解返回的数据类型可以是View或者String类型。 RestController是基于Controller的增强版,它更加适合处理RESTful Web Service。它的返回值是直接作为HTTP Response的Body部分返回给调用者的,不会经过ViewResolver的处理,可以是String、Object、List、Map等任何类型(包括自定义类型),不限制返回值的类型,因此它比Controller更加的灵活。RestController注解会自动将返回值转化为JSON或XML格式,返回给客户端,主要是用于返回数据而非页面。RestController中的方法可以使用GetMapping、PostMapping、PutMapping等注解来响应RESTful请求,可以使用RequestBody注解来将请求体中的数据绑定到一个Java对象上,也可以使用PathVariable注解来获取URL路径中的参数。RestController注解返回的数据类型可以是任何类型。 总的来说,Controller主要用于处理视图层,返回视图类型的数据,而RestController主要用于处理数据层,返回数据类型的数据。所以,如果你要处理RESTful请求,建议使用RestController注解。如果你要处理视图,建议使用Controller注解。 ### 回答3: RestControllerController是Spring MVC框架中两个常用的注解,它们用于定义处理HTTP请求的类。它们之间的主要区别在于它们在处理HTTP请求的方式和返回结果方面的差异。 1. 处理HTTP请求的方式: Controller是用来处理HTTP请求的,通常使用方法来响应请求,你可以使用@RequestMapping或其它HTTP请求映射注解来将请求映射到控制器方法。在控制器方法中,你可以使用@RequestParam或@PathVariable注解来获取请求参数,使用@ResponseBody注解将结果转换为JSON格式返回给客户端。 @RestControllerController和ResponseBody的结合体,它可以用于处理RESTful请求。当使用@RestController注解时,它的所有方法都会默认返回JSON格式的数据,Spring MVC框架会自动将方法返回的数据转换为JSON格式返回给客户端,你不需要再使用@ResponseBody注解来实现JSON的转换。 2. 返回结果方面的差异: Controller默认情况下返回视图,需要在方法上添加@ResponseBody注解才会返回JSON格式的数据。而@RestController注解的控制器方法默认都会返回JSON格式的数据。这两个注解的主要差别在于它们的返回值的类型不同,Controller返回ModelAndView对象或者String类型的视图名,而RestController返回使用@ResponseBody注解的对象或者对象列表。 总之,Controller用于处理普通的HTTP请求,可以返回视图或前端页面等其他类型的数据,而RestController用于处理RESTful请求,返回JSON格式数据或XML格式数据。所以当你需要编写用于一个Web应用程序的API时,使用@RestController是一个非常好的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值