自定义消息解析器, AbstractHttpMessageConverter

概要:

通常在做WEB项目开发, 有安全级别比较高的项目, 参数一般会加密, 或者添加签名, 但在插入数据库之前会做一些校验,  每个方法都添加校验代码,显得有些冗余, 这些都可以通过自定义解析器实现,

1, 代码实现:

sprng.xml 中添加 默认的json解析, 和自定义消息解析

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
		<property name="messageConverters">
			<list>
				<ref bean="mappingJacksonHttpMessageConverter"/>
				<bean class="com.study.test.expand.MyHttpMessageConverter" />
			</list>
		</property>
	</bean>

    <bean id="mappingJacksonHttpMessageConverter"
          class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>text/html;charset=UTF-8</value>
                <value>text/plain;charset=UTF-8</value>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
    </bean>

自定义解析器 Java代码:

public class MyHttpMessageConverter extends AbstractHttpMessageConverter<User> {

	public MyHttpMessageConverter() {
    //注册对应的contentType
		super(new MediaType("application", "type-t", Charset.forName("UTF-8")));
	}
	@Override
	protected boolean supports(Class<?> clazz) {
		// 只处理返回值是User对象的方法
		return User.class.isAssignableFrom(clazz);
	}
	@Override
	protected User readInternal(Class<? extends User> clazz, HttpInputMessage inputMessage) throws IOException,
			HttpMessageNotReadableException {
		String json = StreamUtils.copyToString(inputMessage.getBody(), Charset.forName("UTF-8"));
		if (StringUtils.isEmpty(json)) {
			return null;
		}
		String[] split = json.split(",");
		String name = split[0].split("#")[1];
		String hobby = split[1].split("#")[1];
		User user = new User();
		user.setName(name);
		user.setHobby(hobby);
		return user;
	}
	@Override
	protected void writeInternal(User user, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
		String msg = "自定义类型application/type-t, 名称:" +user.getName() +", 爱好: " + user.getHobby();
		outputMessage.getBody().write(msg.getBytes("UTF-8"));
	}
}
// 实体类
public class User {
	private String name;
	private String hobby;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getHobby() {
		return hobby;
	}
	public void setHobby(String hobby) {
		this.hobby = hobby;
	}
}
// controller
@Controller
@RequestMapping("/home")
public class HomeController {
	@RequestMapping(value = "index3")
	@ResponseBody
	public User index3(@RequestBody User user) {
		return user;
	}
}

PostMan 解析, Headers 里面添加头信息 Content-Type :  application/type-t;charset=UTF-8 

2, 源码解析

2.1, 参数解析,

查看 RequestResponseBodyMethodProcessor 的 readWithMessageConverters 方法,  循环所有解析器,

首先判断是否是GenericHttpMessageConverter 的子类,如果不是, 转换为HttpMessageConverter 接口对象,并调用read方法,

该方法由子类 AbstractHttpMessageConverter 实现, 并最终调用readInternal 方法, 而 readInternal 方法由我们自定义解析器重写,

2.2 方法返回

查看 RequestResponseBodyMethodProcessor的 writeWithMessageConverters 方法,   首先会解析出所有符合的contentType, 循环所有contentType, 选择符合的头信息

循环所有的消息解析器,  判断是否是 GenericHttpMessageConverter的子类, 如果不是直接调用 canWrite 方法, 判断是否可以写,

最终调用write方法, 由子类AbstractHttpMessageConverter 实现, 并调用 writeInternal方法, 这个方法恰好被我们的自定义解析器重写

3, 问题总结

1, spring.xml中自定义的消息解析,  mappingJacksonHttpMessageConverter 在前面, 而canWrite为true,进入循环,执行完后,会return, 并没有执行我们的MyHttpMessageConverter自定义消息器

  解答: 因为在write的过程中, 处理完返回值,直接写入了response中, 所以不会写第二遍,  可以在RequestMapping 注解中, 使用produces 返回指定的类型,   consumes 接受指定的类型

@RequestMapping(value = "index3", produces = { "application/type-t;charset=UTF-8" })

2,  writeInternal 自定义消息器, 往 response 写数据. 出现中文乱码

    解答, 因为消息解析器在写的过程中,默认使用的是ISO8859-1,  而项目中用的是UTF-8 编码格式, 所以返回内容转换一下就行   

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章