处理JSON
对于JSON的处理一般都是基于Ajax前端技术来实现的,可以实现页面的局部刷新数据显示。
在Springmvc处理JSON是非常简单的。
分为三步走:
一、前台提交请求Ajax
二、后台处理请求@ResponseBody
三、前台接收返回的JSON数据 dataType
<!-- 前台提交请求 一般都是利用ajax -->
<a href="testJson" id="testjson">Test JSON</a>
$(function(){
$("#testjson").click(function(){
var url= this.href;
var args= {};
$.ajax({
url:url,
type:'post',
dataType:'json',
success:function(data){
for(var i=0;i<data.length;i++){
var id= data[i].id;
var lastName=data[i].lastName;
alert(id+":"+lastName);
//$("#two").append(data);
}
}
});
return false;
});
})
<!-- 后台处理 -->
// 测试JSON 注意返回的数据
@ResponseBody
@RequestMapping("/testJson")
public Collection<Employee> testJson(){
System.out.println("test JSON");
return employeeDAO.getAll();
}
注意:进行ajax数据提交的时候,在后台我们的数据不能再存放在Map集合中了,这是因为,存放Map集合中 的数据需要进行页面刷新或者页面跳转才能显示数据,而我们利用的Ajax异步传输。
注意:我们返回的值,直接是我们前台所需要的数据。而不再需要进行视图渲染,所以我们也是添加了注解@ResponseBody。
Jackson简介
JackSon框架类似于json-lib框架(struts2提供了集成json-lib的插件),都是讲Java对象与JSON对象之间的转换。但是相比json-lib框架,Jackson所依赖的jar包较少。
Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。
对于Jackson来讲,只需要导入三个jar包就可以实现JSON的转换【jackson-databind-2.4.0】【jackson-core-2.4.0】【jackson-annotations-2.4.0】,所以在我们编写上面代码时,不要忘记进行jar包的导入。
jackson 框架提供了JsonGenerator ,ObjectMapper两个类通过这两个类提供的方法可以将java 对象转化为json 对象,json 数组格式,也可以将json对象、数组格式转化为java对象。
HttpMessageConverter基础概念
为什么能够处理JSON ,对于Spring3.0 ,新增了一个接口HttpMessageConverter[T],这个接口负责将请求转化为一个对象(类型为T),将对象(类型为T)输出为响应信息。
HttpMessageConverter[T]接口中定义了一些方法(在代码中可以搜索HttpMessageConverter进行查看):
【boolean canRead(Class[ ? ] clazz, MediaType mediaType)】:指定转换器可以读取的对象类型,即转换器是否可以将请求信息转化为Clazz类型的对象,同时指定支持MIEI类型(text/html,application/json等)。
【boolean canWrite(Class[ ? ] clazz, MediaType mediaType)】:指定转换器是否可以将Clazz类型的对象写入到响应流中,响应流支持的媒体类型在MediaType中定义。
【List[MediaType] getSupportedMediaTypes()】:该转换支持的媒体类型。
【T read(Class[? extends T] clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException 】:将请求信息流转化为T类型的对象。
【void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException】:将T类型的对象写到响应流中,同时指定相信的媒体类型为contentType
HttpMessageConverter工作原理流程 查看【HttpInputMessage】和【HttpOutputMessage】
HttpMessageConverter接口的实现类
查看Springmvc装配了那些实现类。
在我们测试的testJSON方法中打上断点,debug之后,我们可以向前找到dispatchServlet,然后变量域中找到【this】【handlerAdapters】【elementData中的RequestMappingHandlerAdapter】【MessageConverters】
HttpMessageConverter使用方式
使用HttpMessageConverter[T]能做些什么呢? 使用这个我们可以将请求信息转化并绑定到处理方法的入参中,或者,响应结果转化为对应类型的响应信息,注意是请求信息的处理和转化为对应的类型的响应信息,spring 提供了两种路径:
使用【@ResponseBody】和【@RequestBody】对处理方法进行标注
使用【HttpEntity[T]】和【ResponseEntity[T]】作为处理方法的入参和返回值。
当控制器处理的方法使用到上述四个注解时,Spring 首先根据请求头和响应头的Accept属性(HTTP协议)选择匹配的HttpMessageConverter(上面的默认实现类),进而根据参数类型或者泛型类型的过滤得到匹配的HttpMessageConverter,如果找不到可用的如果找不到可用的将报错。
【@ResponseBody】和【@RequestBody】【HttpEntity[T]】和【ResponseEntity[T]】不需要成对出现。
@RequestBody 将HTTP请求正文转换为适合的HttpMessageConverter对象。
@ResponseBody 将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMessageConverter的Adapter转换对象,写入输出流。
实例一 读取文件内容。类似于上传效果的使用:
<!--前台提交数据 -->
<form action="testHttpMessageConverter" method="post" enctype="multipart/form-data">
File:<input type="file" name="file"/><br>
Desc:<input type="text" name="desc"/>
<input type="submit" value="submit">
</form>
<!-- 后台进行处理 -->
// 类似于上传工作
//此时利用的是StringHttpMessageConverter 将请求信息转换为字符串
@RequestMapping("/testHttpMessageConverter")
public String testHttpMessageConverter(@RequestBody String body){
System.out.println(body);
return "Hello HttpMessage"+new Date();
}
实例二 实现文件下载
<!-- 前台数据连接 -->
<a href="TestResponseEntity">TestResponseEntity</a>
<!-- 后台数据处理下载 -->
@RequestMapping("/TestResponseEntity") // 类似于下载
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException{
byte []body=null;
ServletContext context = session.getServletContext();
InputStream in = context.getResourceAsStream("/files/abc.txt");
body = new byte[in.available()];
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=abc.txt");
// 设置响应头 为下载
HttpStatus stateCode = HttpStatus.OK;
ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(body,headers,stateCode);
return response;
}
国际化
默认情况下,Springmvc会根据请求中的Accept-Language参数判断客户端的本地化类型(HTTP协议)。当接受到请求时Springmvc会在上下文找一个本地化解析器(LocalResolver),找到后使用他获取请求所对应的本地化类型信息。Springmvc还允许装配一个动态更改本地化类型的拦截器。这也是我们所在springmvc.xml中所配置的文件,这样就通过指定一个请求参数就可以控制单个请求的本地化类型。
本地化解析器和本地化拦截器
【AcceptHeaderLocaleResolver】:根据http请求头的Accept-Language确定本地化类型,Springmvc使用该解析器。
【CookieLocaleResolver】:指定的cookie值确定本地化类型。
【SessionLocalResolver】:根据session中特定的属性确定本地化类型。
【LocaleChangeInterceptor】:从请求参数中获取本次请求对应的本地化类型。
他们在配置文件中进行使用。
关于国际化
作用:
1、在页面上能够根据浏览器语言设置的情况对文本(不是内容),时间,数值进行本地化处理
2、 可以在bean中获取国际化资源文件,Locale 对应的消息(使用时注意配置文件要关闭)
3、 可以通过超链接切换Locale (切换语言) 而不用浏览器的语言设置情况
解决
1、 使用JSTL 的fmt 标签,对国际化字段进行显示。
2、 在bean中注入ResourceBundleMessageSource的实例,使用其对应的getMessage方法即可
3、 配置SessionLocaleResource 和LocaleChangeInterceptor
注意上述的作用和解决方案一一对应
<!-- spring.xml配置文件 -->
<!-- 配置国际化资源文件 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
<!-- 配置 SessionLocaleResolver -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
</bean>
<!-- 配置拦截器 LocaleChangeInterceptor-->
<mvc:interceptors>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
</mvc:interceptors>
<!--直接跳转到页面,不经过Controller -->
<!-- <mvc:view-controller path="/i18n" view-name="i18n" /> 获取资源时,利用Controller 所以屏蔽 -->
<mvc:view-controller path="/i18n2" view-name="i18n2" />
<!-- 前台链接一 -->
<a href="i18n"> I18N Page </a> // 第一页面 index.jsp 跳转第二页面
<!-- 前台链接二 --> // 第二页面 i18n.jsp 注意上面的直接跳转配置
<fmt:message key="i18n.username"></fmt:message> // 国际化显示
<a href="i18n2"> I18N2 Page </a>
<br>
<a href="i18n?locale=zh_CN"> 中文 </a>
<br>
<a href="i18n?locale=en_US"> English</a>
<br>
<!-- 前台链接三 --> // 第三页面 i18n2.jsp
<fmt:message key="i18n.password"></fmt:message>
<a href="i18n"> I18N Page </a>
<!-- 后台处理代码 -->
@Autowired
private ResourceBundleMessageSource messageSource;
@RequestMapping("/i18n")
public String Testi18n(Locale locale){ // Locale 入参
String val = messageSource.getMessage("i18n.username", null, locale);
System.out.println(val);
return "i18n";
}
文件上传
对于文件上传Springmvc提供了直接的支持!这种支持是通过即插即用的MultipartResolver,Springmvc用Jakarta Commons FileUpload技术实现了一个【MultipartResolver】实现类:【CommonsMultipartResolver】。
Springmvc 上下文中默认没有装配【MultipartResolver】因此,默认情况下事不能处理文件的上传工作。如果想使用Springmvc的文件上传功能,需要在上下文进行配置【MultipartResolver】。
分为四步走:
第一步:加入jar包
第二步:配置文件
第三步:前台文件提交
第四步:后台数据处理
第一步:加入jar包
由于我们使用Jakarta Commons FileUpload技术,所以我们要加入需要的jar包【commons-fileupload-1.2.1】【commons-io-2.0.1】注意fileupload依赖io所以也要进行加入。
第二步:配置文件:
<!--文件的上传 -->
<!-- 配置 CommonsMultipartResolver 具体的属性配置去源码中查看,注意编码的问题 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000000000"></property>
</bean>
可配置属性
第三步:前台文件提交
<p>FileUpload</p>
<form action="TestFileUpload" method="post" enctype="multipart/form-data">
File:<input type="file" name="file01"/><br>
Desc:<input type="text" name="desc01"/>
<input type="submit" value="submit">
</form>
第四步:后台数据处理
利用入参MultipartFile 类型用来接收文件的相关信息
@RequestMapping("/TestFileUpload")
public String TestFileUpload(@RequestParam(value="desc01",required=false) String desc,
@RequestParam("file01") MultipartFile file ) throws Exception{
//参数MultipartFile 用来传递文件的相关信息
System.out.println("desc:"+desc);
System.out.println("OriginalFilename"+file.getOriginalFilename());
System.out.println("getInputStream"+file.getInputStream());
InputStream inputStream = file.getInputStream();
if(file.isEmpty()){
file.transferTo(new File("d:\\"+file.getOriginalFilename()));
// 文件写入地点
}
return "success";
}
注意的是HttpMessageConverter是不能做文件上传的,但是他能分辨出那个是文件