環境:
使用spring mvc 配置json消息轉換器為MappingJackson2HttpMessageConverter
發現long類型的數據到了js端會丟失精度
解決方案:
將long統一轉為string類型
方法一:
數據層轉換,由於項目使用了spring 的jdbc模版類,查詢時調用了spring的query方法
public <T> List<T> query(String sql, SqlParameterSource paramSource, RowMapper<T> rowMapper) throws DataAccessException { return getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rowMapper); }
這個方法有個參數rowMapper,我用來將數據庫數據轉換為Map,我通過自定義實現RowMapper接口,將mysql數據庫里的bigint類型轉為string而不是默認的long,代碼如下:
public class HashMapRowMapper implements RowMapper<Map<String, Object>> { @Override public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException { ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); Map<String, Object> mapOfColValues = new LinkedCaseInsensitiveMap<Object>(columnCount); for (int i = 1; i <= columnCount; i++) { String key = JdbcUtils.lookupColumnName(rsmd, i); Object obj = JdbcUtils.getResultSetValue(rs, i); if (obj == null) { mapOfColValues.put(key, obj); } if (obj != null) { Class<?> cc = obj.getClass(); if (cc.getName().equals("java.math.BigInteger") && obj != null) { mapOfColValues.put(key, String.valueOf(obj)); } else { mapOfColValues.put(key, obj); } } } return mapOfColValues; } }
調用代碼如下,注意query傳入的最后一個參數使用了自定已類HashMapRowMapper:
public Map<String, Object> getItem(Map<String, Object> inParam) { if (MapUtil.getValue("id", inParam) == "") throw new InParamCheckException("id不能為空:" + inParam.get("id")); String orgId = MapUtil.getValue("org_id", inParam); String appId = IDConstants.APP_ID_PIS; NamedParameterJdbcTemplate jdbc = jdbcRouteHelper.getJDBCTemplate(orgId, appId); return new MyMap().put("simple_info", jdbc.query("select * from simple_info where id=:id", inParam, new HashMapRowMapper())) .put("simple_test", jdbc.query("select * from simple_test where simple_info_id=:id", inParam, new HashMapRowMapper())) .getMap(); }
方法二:
配置spring的消息轉換器的ObjectMapper為自定義的類
配置如下:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="LongToStringJsonConverter"> <property name="supportedMediaTypes"> <list> <value>application/json;charset=UTF-8</value> <value>text/html;charset=UTF-8</value> <value>text/plain;charset=UTF-8</value> </list> </property> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" /> </bean> </property> </bean> </property> </bean> </bean>
其中LongToStringJsonConverter為自定義轉換器
public class LongToStringJsonConverter extends ObjectMapper { /** * */ private static final long serialVersionUID = 1683531771040674386L; @Override public ObjectMapper registerModule(Module module) { SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(Long.class, ToStringSerializer.instance); simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); return super.registerModule(simpleModule); } }
spring中controller層的代碼使用時無需特別修改,下面是一個controller類里返回json數據,代碼不做任何修改,long類型已經轉為string返回到web瀏覽器了.
@RequestMapping("/") @ResponseBody public Map<String, Object> init() { List<Object> lstDoctor = dictConsumer.getBaseParam().getItemsFromCache(cache_keys.PIS_doctor.name(), test_org_id, IDConstants.APP_ID_PIS); List<Object> lstSubjectType = dictConsumer.getBaseParam().getItemsFromCache(cache_keys.PIS_subject_type.name(), test_org_id, IDConstants.APP_ID_PIS); List<Object> lstTest = dictConsumer.getBaseParam().getItemsFromCache(cache_keys.PIS_test.name(), test_org_id, IDConstants.APP_ID_PIS); MyMap map = new MyMap(); map.put("doctors", lstDoctor).put("subject_types", lstSubjectType).put("tests", lstTest); return map.getMap(); }