HttpMessageConverter解析

1、前言

主要分析HttpMessageConverter接口、@RequestMapping中的一些属性、@ResponseBody注解、@RequestBody注解以及Json的收发,通过ajax了解这些东西如何在一起使用;如何搭配使用、分别有什么作用、担任什么职责…

  • @RequestMapping注解:请求映射专家,主要负责URI到Controller的映射,以及一些响应的方式、数据格式等的设置…

  • @ResponseBody注解:在Controller响应方法上加入该注解,就会跳过视图解析器;将返回值直接以RequestMapping指定的格式或者MVC配置好的格式响应出去!

  • @RequestBody注解:使用在参数上,将前端响应的数据直接转换为Controller之中的参数(可以是pojo类)…

  • HttpMessageConverter接口:该接口拥有很多实现类、具体的作用就是针对请求与响应的数据进行格式之间的转换!



2、HttpMessageConverter接口

先看一下接口的源代码,对源代码进行分析一波。

public interface HttpMessageConverter<T> {

	boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

	T read(Class<? extends T> clazz, HttpInputMessage inputMessage);
			
	boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

	void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage);
			
	List<MediaType> getSupportedMediaTypes();

	default List<MediaType> getSupportedMediaTypes(Class<?> clazz);
}
  • MediaType类:表示互联网中多媒体数据类型的格式;例如:text/html,text/plain,application/json…

  • @Nullable注解:带有该注解修饰的参数表示该参数可以没有,如果没有就会采用默认的值!

  • canRead方法:检查clazz对象是否能转换为mediaType表示的数据类型,这个mediaType是前端页面请求时设定的contentType格式!

  • read方法:如果canRead方法返回值为true则调用read方法将数据进行格式转换!

  • canWrite方法:检查clazz对象是否能转换为mediaType类型,此时的mediaType表示后端想要响应给前端的数据格式!

  • write方法:如果canWrite返回值为true,则将数据进行格式的转换然后响应!

  • 其他:另外两个方法是针对媒体类型进行查看的,媒体类型点进去有非常多的类型…



3、mvc注解驱动

默认情况下SpringMVC框架在配置文件中不进行该注解驱动的支持情况下,会默认给应用使用4个实现类用于接受/响应数据的转换,在开启后会增加到7个左右(版本不同)。
在这里插入图片描述
只需要重点关注蓝色的String以及Json格式的转换。

3.1、不开启驱动

在这里插入图片描述

在前端控制器DispatcherServlet类中的HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());中打上断点进行debug即可看到默认是开启的四个实现类用于基本消息数据的转换。

3.2、开启注解驱动

在springmvc的核心额皮质文件中加入这句话继续debug。

<mvc:annotation-driven></mvc:annotation-driven>

在这里插入图片描述
可以看到开启之后有8个实现类参与,但是这些实现类都没有进行编码集的设置,而是采用了默认的编码集。

3.3、配置注解驱动

一般情况下会配置json和字符串的编码格式,以降低乱码的几率。

<mvc:annotation-driven>
	<mvc:message-converters register-defaults="true">
		<bean class="org.springframework.http.converter.StringHttpMessageConverter">
			<constructor-arg value="UTF-8"/>
		</bean>
	<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
		<property name="objectMapper">
			<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
				<property name="failOnUnknownProperties" value="false"/>
			</bean>
		</property>
		<property name="defaultCharset" value="UTF-8"/>
	</bean>
	</mvc:message-converters>
</mvc:annotation-driven>


4、ajax请求与设置

ajax请求中前后端规定的数据格式尽量一一对应,当开启注解驱动之后所有的json前后交换与解析不再需要手动通过ObjectMapper进行对数据的解析与封装,直接返回对象即可得到解析。

<script src="${pageContext.request.contextPath}/js/jquery-3.4.1.js"></script>
<script>
    function sub(){
        var user = {
            "username" : $('#username').val(),
            "password" : $('#password').val(),
        }
        $.ajax({
            url: "${pageContext.request.contextPath}/ajax/test",
            type: "POST",
            data: JSON.stringify(user),
            contentType: "application/json;charset=utf-8",
            dataType : "json",
            success: function (data){
                alert(data)
            }
        })
    }
</script>
<div>
    <form action="${pageContext.request.contextPath}/ajax/test" method="post">
        用户名: <input type="text" id="username" required>
        密码: <input type="text" id="password" required>
        <input type="button" value="提交" onclick="sub()">
    </form>
</div>

只需要这样写即可,json的解析与封装由于在xml中配置了驱动的支持,全部都由框架自动完成!

@RequestMapping(value = "/test")
@ResponseBody
public Account test (@RequestBody Account account){        //将json格式数据自动转换为pojo对象
    System.out.println(account.toString());
    return account;        //配置文件自动进行转换
}

执行顺序:

  1. 发起请求,框架先找到HttpMessageConverter接口的实现类调用canRead方法以及read方法解析json数据。

  2. 然后根据@RequestBody注解将对应的数据自动封装到对应的pojo中,注意这里需要使得数据的属性名与请求的参数一致!

  3. 框架根据控制器方法的返回值类型,找到HttpMessageConverter接口的实现类。最后找到MappingJackson2HttpMessageConverter。

  4. 使用MappingJackson2HttpMessageConverter实现类先执行canWrite方法进行判断,然后在执行write方法,把account对象转换为json格式的数据。

  5. 最后框架使用@ResponseBody注解,把转换后的json输出给浏览器进行响应!在这里插入图片描述

补充:

当然也可以不使用框架的配置,进行手动实现;处理解析与封装的时候手动使用jackson包,并且在RequestMapping中设置produces的返回值类型也能做到。

@RequestMapping(value = "/t", produces = "application/json;charset=utf-8")
@ResponseBody
public String t (String data) throws JsonProcessingException {        //data是json格式
    System.out.println(data);
    ObjectMapper mapper = new ObjectMapper();
    JsonNode root = mapper.readTree(data);
    String username = root.path("username").asText();
    String password = root.path("password").asText();
    System.out.println(username + ": " + password);
    Account account = new Account(username, password);
    return mapper.writeValueAsString(account);
}

在这里插入图片描述



  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值