Spring 4.2.4.RELEASE MVC 学习笔记 - 8.1 - text/gson
为了学习spring mvc框架整合fasterxml jackson工具,实现Restfull模式api实现对json、xml的支持。我们需要对之前对gson支持做一些改动,以免混淆视听。
修改测试请求URL
修改原来的user.html页面中的测试URL,将/api/userAdd.json修改为/api/userAdd.gson,/api/userQuery.json修改为/api/userQuery.gson。因为在Spring mvc 整合 fasterxml jackson工具的时候,框架上默认支持的一种情况就是以*.json为后缀的请求,这样修改避免弄混。
/framework_spring/src/main/webapp/user.html
<div class="vform">
<div class="h1">HTTP POST 添加用户 /api/userAdd.gson</div>
<form action="/api/userAdd.gson" method="post">
<div>
<label>用户名:<input name="username" value="xiaohong" /></label>
</div>
<div>
<label> 姓名:<input name="name" value="小红" /></label>
</div>
<div>
<label>年龄:<input name="age" value="22" /></label>
</div>
<div>
<label>性别:<select name="sex"><option value="0" selected="selected">女</option></select></label>
</div>
<div>
<button type="submit">添加新用户</button>
</div>
</form>
<hr />
</div>
<div class="vform">
<div class="h1">HTTP GET 查询用户 /api/userQuery.gson</div>
<form action="/api/userQuery.gson" method="get">
<div>
<label> 用户名:<input name="username" value="xiaohong" /></label>
</div>
<div>
<button type="submit">查询</button>
</div>
</form>
<hr />
</div>
<div class="clearfloat"></div>
</div>
修改UserController处理方法
修改原来UserController类中的方法userAddJson方法为userAddGson,同时修改对应的注解。详细参见下面的代码。
修改方法名字,属于个人习惯问题。
修改@RequestMapping注解,path = “/userAdd.gson”、produces = “text/gson; charset=UTF-8”,需要重点说明一下,path用于接收userAdd.gson过来的请求,produces则通过此信息控制调用自定义的Gson数据解析器解析数据。
cn.vfire.framework.spring.mvc.controller.UserController
@RequestMapping(path = "/userAdd.gson", method = RequestMethod.POST, produces = "text/gson; charset=UTF-8")
@ResponseBody
public Result userAddGson(UserMode user) {
XModelAndView modeView = new XModelAndView();
modeView.addObject("user", user);
System.out.println(String.format("添加用户%s完成", user.getName()));
return modeView.toResult();
}
@RequestMapping(path = "/userQuery.gson", method = RequestMethod.GET, produces = "text/gson; charset=UTF-8")
@ResponseBody
public Result userQueryGson(String username) {
XModelAndView modeView = new XModelAndView();
UserMode user = new UserMode();
{
user.setUsername(username);
user.setName("小红");
user.setAge(22);
user.setSex(0);
}
modeView.addObject("user", user);
System.out.println(String.format("查询用户名为%s用户 信息成功", user.getUsername()));
return modeView.toResult();
}
修改自定义数据解析器GSONHttpMessageConverte
修改原自定义Gson数据解析器GSONHttpMessageConverte类的构造方法,指定该解析器只处理MediaType=”text/gson; charset=UTF-8”的请求Requeset和应答Response。
cn.vfire.framework.spring.mvc.converter.GSONHttpMessageConverte
public GSONHttpMessageConverte(Charset defaultCharset) {
super(new MediaType("text", "gson", defaultCharset));
this.availableCharsets = DEFAULT_CHARSET;
this.dateFormat = DEFAULT_DATEFORMAT;
log.debug(String.format("注册自定义%s数据解析器,解析MediaType类型为%s。",GSONHttpMessageConverte.class.getName(),"application/json"));
log.debug(String.format("默认处理字符集%s。",DEFAULT_CHARSET));
log.debug(String.format("默认处理日期类型数据格式化%s。",DEFAULT_DATEFORMAT));
}
PS:我偷偷的在这个类的方法中追加了日志打印,下面我还是列出该类的全部代码共大家参考把。
cn.vfire.framework.spring.mvc.converter.GSONHttpMessageConverte
package cn.vfire.framework.spring.mvc.converter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import org.apache.log4j.Logger;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.StreamUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
public class GSONHttpMessageConverte extends AbstractHttpMessageConverter<Object> {
private static final Logger log = Logger.getLogger(GSONHttpMessageConverte.class);
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public static final String DEFAULT_MEDIATYPE = "text/gson" ;
public static final String DEFAULT_DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
private GsonBuilder gsonBuilder = new GsonBuilder();
@Getter
@Setter
public Charset charset = DEFAULT_CHARSET ;
private List<MediaType> mediaTypes = new LinkedList<MediaType>() ;
@Getter
@Setter
private String dateFormat = DEFAULT_DATEFORMAT;
@Getter
@Setter
private boolean writeAcceptCharset = true;
@Getter
@Setter
private boolean excludeFieldsWithoutExposeAnnotation = false;
public GSONHttpMessageConverte() {
this.setCharset(DEFAULT_CHARSET);
this.setMediaTypes(DEFAULT_MEDIATYPE);
this.setDateFormat(DEFAULT_DATEFORMAT);
log.debug(String.format("注册自定义%s数据解析器,解析MediaType类型为%s。", GSONHttpMessageConverte.class.getName(), this.charset.toString()));
log.debug(String.format("默认处理字符集%s。", DEFAULT_CHARSET));
log.debug(String.format("默认处理日期类型数据格式化%s。", DEFAULT_DATEFORMAT));
}
protected List<Charset> getAcceptedCharsets() {
List<Charset> charsetList = new ArrayList<Charset>(1);
charsetList.add(this.charset);
return charsetList;
}
@Override
protected Long getContentLength(Object t, MediaType contentType) throws IOException {
Long contentLength = super.getContentLength(t, contentType);
log.debug("进入自定义" + GSONHttpMessageConverte.class.getName() + "数据解析器,内容长度为" + contentLength + "。");
return contentLength;
}
private Charset getContentTypeCharset(MediaType contentType) {
if (contentType != null && contentType.getCharSet() != null) {
return contentType.getCharSet();
} else {
return this.charset;
}
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return Collections.unmodifiableList(this.mediaTypes);
}
@Override
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
Charset charset = this.getContentTypeCharset(inputMessage.getHeaders().getContentType());
Object rs = StreamUtils.copyToString(inputMessage.getBody(), charset);
log.debug(String.format("进入自定义%s数据解析器,处理字符集%s,读取数据流到到对象%s。", GSONHttpMessageConverte.class.getName(), String.valueOf(charset), String.valueOf(rs)));
return rs;
}
public void setMediaTypes(List<String> mediaTypes) {
if(mediaTypes!=null && mediaTypes.isEmpty()==false){
for(String media : mediaTypes){
this.setMediaTypes(media);
}
}
}
public void setMediaTypes(String mediaTypes) {
if(this.mediaTypes.indexOf(mediaTypes)==-1){
MediaType mt = MediaType.valueOf(mediaTypes);
this.mediaTypes.add(new MediaType(mt.getType(),mt.getSubtype(),this.charset)) ;
}
}
@Override
protected boolean supports(Class<?> clazz) {
return true;
}
private String toJson(Object o) {
try {
if (this.excludeFieldsWithoutExposeAnnotation) {
this.gsonBuilder = this.gsonBuilder.excludeFieldsWithoutExposeAnnotation();
}
Type genericType = TypeToken.get(o.getClass()).getType();
Gson gson = gsonBuilder.setDateFormat(this.dateFormat).create();
String json = gson.toJson(o, genericType);
if (json == null || "".equals(json.trim())) {
json = "{}";
}
return json;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
@Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
if (this.writeAcceptCharset) {
outputMessage.getHeaders().setAcceptCharset(this.getAcceptedCharsets());
}
Charset charset = this.getContentTypeCharset(outputMessage.getHeaders().getContentType());
StreamUtils.copy(this.toJson(o), charset, outputMessage.getBody());
log.debug(String.format("进入自定义%s数据解析器,处理字符集%s,解析对象%s到Json。", GSONHttpMessageConverte.class.getName(), String.valueOf(charset), String.valueOf(o)));
}
}
测试
测试表单
后台日志
添加用户小红完成
@DEBUG|2016-03-08 12:28:28,755|cn.vfire.framework.spring.mvc.converter.GSONHttpMessageConverte.getContentLength(GSONHttpMessageConverte.java:72)|http-bio-8000-exec-6
Info:进入自定义cn.vfire.framework.spring.mvc.converter.GSONHttpMessageConverte数据解析器,内容长度为null。
@DEBUG|2016-03-08 12:28:28,758|cn.vfire.framework.spring.mvc.converter.GSONHttpMessageConverte.writeInternal(GSONHttpMessageConverte.java:135)|http-bio-8000-exec-6
Info:进入自定义cn.vfire.framework.spring.mvc.converter.GSONHttpMessageConverte数据解析器,处理字符集UTF-8,解析对象cn.vfire.framework.spring.mvc.view.Result@1aa8430a到Json。