这篇文章主要围绕如何在SpringMVC中为特定类自定义JSON和springmvc自定义参数解析展开,旨在为您提供一份详细的参考资料。我们将全面介绍如何在SpringMVC中为特定类自定义JSON的
这篇文章主要围绕如何在SpringMVC中为特定类自定义JSON和springmvc自定义参数解析展开,旨在为您提供一份详细的参考资料。我们将全面介绍如何在SpringMVC中为特定类自定义JSON的优缺点,解答springmvc自定义参数解析的相关问题,同时也会为您带来19. SpringBoot 扩展 SpringMVC功能、 接管、自定义SpringMVC、blob类型数据如何在springmvc中获取显示、json – 在Spring 3 MVC下的Jackson自定义序列化、Spring MVC中使用FastJson自定义注解的实用方法。
本文目录一览:- 如何在SpringMVC中为特定类自定义JSON(springmvc自定义参数解析)
- 19. SpringBoot 扩展 SpringMVC功能、 接管、自定义SpringMVC
- blob类型数据如何在springmvc中获取显示
- json – 在Spring 3 MVC下的Jackson自定义序列化
- Spring MVC中使用FastJson自定义注解
如何在SpringMVC中为特定类自定义JSON(springmvc自定义参数解析)
我正在使用SpringMVC并具有以下方法。
@RequestMapping("/login")public @ResponseBody User login(User user) { // some operation here .... return user;}
在大多数情况下,SpringMVC以适当的方式将对象转换为JSON。但是有时您可能需要自定义JSON。在哪里可以为所有User对象自定义JSON。我希望将User对象转换为JSON的行为在所有方面都保持一致。我想一个监听器或接口可以实现。是否存在这种解决方案?
PS。如果我要转换的对象是第三方类的实例怎么办?我无法在类定义中自定义它,因为我没有源代码…
答案1
小编典典Spring默认使用Jackson来序列化和反序列化JSON。您可以@JsonSerialize
在User
类型上使用Jackson的批注,并提供一个JsonSerializer
实现所需序列化的实现。
19. SpringBoot 扩展 SpringMVC功能、 接管、自定义SpringMVC
编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型;不能标注@EnableWebMv:
既保留了所有的自动配置,也能用我们扩展的配置;
如下代码:【拓展 请求 映射 页面 功能】
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能 @Configuration public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { // super.addViewControllers(registry); //浏览器发送 /bihu 请求来到 Thymeleaf 页面 registry.addViewController("/bihu").setViewName("Thymeleaf"); } }
原理:
1)、WebMvcAutoConfiguration是SpringMVC的自动配置类
2)、在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)
@Configuration public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration { private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); //从容器中获取所有的WebMvcConfigurer @Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); //一个参考实现;将所有的WebMvcConfigurer相关配置都来一起调用; @Override // public void addViewControllers(ViewControllerRegistry registry) { // for (WebMvcConfigurer delegate : this.delegates) { // delegate.addViewControllers(registry); // } } } }EnableWebMvcConfiguration
3)、所以:容器中所有的WebMvcConfigurer都会一起起作用;
4)、我们的配置类也会被调用;
效果:SpringMVC的自动配置和我们的扩展配置都会起作用;
所以这就达成了 拓展SpringBoot 中 SpringMVC的功能
全面接管SpringBoot中的 SpringMVC:
SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了
我们需要在配置类中添加@EnableWebMvc即可;
package com.bihu.springboot.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; //使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能 //使用EnableWebMvc注解后 SpringBoot中SpringMVC的配置全部失效 都需要自己配,例如 下面的 请求bihu 跳到Thymeleaf页面 就是自己配的,,,你如果在static放(静态资源目录)html,也不可以直接访问 @EnableWebMvc @Configuration public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { // super.addViewControllers(registry); //浏览器发送 /bihu 请求来到 Thymeleaf registry.addViewController("/bihu").setViewName("Thymeleaf"); } }
原理: 为什么@EnableWebMvc自动配置就失效了;
1)@EnableWebMvc的核心
@Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc {
2)、
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
3)、
@Configuration @ConditionalOnWebApplication @ConditionalOnClass({ Servlet.class, dispatcherServlet.class, WebMvcConfigurerAdapter.class }) //容器中没有这个组件的时候,这个自动配置类才生效 主要看这里!!!!这个条件注解这里 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ dispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration {
4)、@EnableWebMvc将WebMvcConfigurationSupport组件导入进来;
5)、导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;
如何修改SpringBoot的默认配置
模式: 1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如 果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默 认的组合起来;
2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置
blob类型数据如何在springmvc中获取显示
blob类型是数组类型,展示在前端需要转成字符串类型
使用方法可以在实体类中定义一个新的String类型的字段,然后通过get方法得到blob类型字段的值,然后后面的操作都使用这个新的字段即可
private byte[] contentText;
private String contentTextShow;
public String getContentTextShow() {
return new String(contentText,StandardCharsets.UTF_8);
}
如果想要使用blob字段的部分数据,可以通过正则表达式去完成
json – 在Spring 3 MVC下的Jackson自定义序列化
我有几个POJO看起来像这样:
class Items {
List
我希望能够使用自定义格式序列化Item中的Date字段(在日期中添加前缀,例如“Date:xxx”),但我不想总是这样做(因为它被其他消费者使用)它不需要此前缀),仅在特定情况下.
如果我使用@JsonSerialize(使用= CustomDateSerializer.class)注释Item的getInsertionDate()我可能会使这个工作,但是,我不想这样做,因为我不总是想要使用此方法序列化此字段,仅在特定情况下.
理想情况下,我会在我想要自定义序列化的控制器中执行此操作:
@JsonSerialize(using = CustomDateSerializer.class)
public List
其中CustomDateSerializer扩展了SerializerBase< Date>并且Jackson会发现它应该使用默认的序列化程序序列化List中的每个项目,当它遇到Date对象时它应该使用我的自定义序列化程序.当然这不起作用,因为不是如何使用@JsonSerialize,但有没有办法让这个工作不是用包装器包装Item并在我想要自定义序列化时使用该包装器?我是否以错误的方式思考这个问题,还有另一种方法可以做到这一点吗?
请注意,我正在使用Spring MVC,所以我不是直接调用序列化.
任何帮助将非常感激 :)
最佳答案
问题是如果它是服务端点方法,杰克逊没有在getItems()上看到注释;它通常只传递类型List< Item>春天决定.使用JAX-RS(如Jersey),可以传递与该方法相关的注释(也许Spring也有一些方法);虽然它需要来自集成代码(对于JAX-RS,Jackson JAX-RS JSON提供程序模块)的更多支持来传递它.
实际创建单独的POJO(而不是传递List类型)可能更容易,以便您可以添加必要的注释.
如果您直接使用Jackson,您还可以使用ObjectWriter并指定要使用的默认日期格式.但是我不知道Spring是否允许你这样做(大多数框架都没有,只暴露了ObjectMapper的可配置性).
还有一个注意事项 – 您可以使用Dates(和Jackson 2.x)上的简单注释代替自定义序列化程序(和/或反序列化程序):
public class DateStuff {
@JsonFormat(shape=JsonFormat.Shape.STRING,pattern="'Date:'yyyy'-'MM'-'dd")
public Date date;
}
指定每个属性格式覆盖.
Spring MVC中使用FastJson自定义注解
最近在做.net转译成Java。其中遇到一个很蛋疼的问题。以前.net属性名都是首字母大写。造成返回给客户端的JSON字符串属性名称都是首字母大写。为了和前端对接我们以前都是如下图所示做法
public class User {
@JSONField(name = "Name")
private String name;
@JSONField(name = "Age")
private BigDecimal age;
@JSONField(name = "Id")
private String id;
@JSONField(name = "isGirl")
private boolean girl;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public BigDecimal getAge() {
return age;
}
public void setAge(BigDecimal age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGirl() {
return girl;
}
public void setGirl(boolean girl) {
this.girl = girl;
}
}
在每个属性上加上JSONField来定义属性名称,特别的繁琐而且还容易出错。下面我将使用FastJson的自定义注解,通过一个注解来实现。
首先用过继承 WebMvcConfigurationSupport 类来实现一个自定义配置类
package com.raiden;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.raiden.filter.DataToStringFilter;
import com.raiden.filter.FirstLetterCapitalizedFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
@Configuration
public class ExtWebMvcConfigurerAdapter extends WebMvcConfigurationSupport {
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//new一个自定义的转换器
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonMessageConverter();
//过滤器链 其中2个是自定义的过滤器
SerializeFilter[] filters = {new FirstLetterCapitalizedFilter(), new DataToStringFilter()};
//将过滤器链放入自定义转换器中
fastJsonHttpMessageConverter.getFastJsonConfig().setSerializeFilters(filters);
//将转换器放入转换器链中
converters.add(fastJsonHttpMessageConverter);
//将转换器链放入配置管理器中
super.configureMessageConverters(converters);
}
}
下面是自定义转换器 其实很简单都不用做什么,只要简单的继承下就好了
package com.raiden;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
/**
*自定义转换器
*/
public class FastJsonMessageConverter extends FastJsonHttpMessageConverter {
}
下面是2个自定义的过滤器
如果要处理属性名称则继承NameFilter
一下代码进行了第二次修订,主要是为了防止和JSONField注解冲突
package com.raiden.fastjson.filter;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.NameFilter;
import com.raiden.fastjson.util.FieldNameUtils;
import com.raiden.fastjson.annotation.FirstLetterCapitalized;
import com.raiden.fastjson.annotation.Ignore;
import com.raiden.fastjson.util.FieldUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
/**
* @创建人:Raiden
* @Descriotion:该过滤器针对属性名,首字母大写过滤器
* @Date:Created in 9:54 2019/6/22
* @Modified By:
*/
public class FirstLetterCapitalizedFilter implements NameFilter {
@Override
public String process(Object instance, String name, Object value) {
if (null == instance || StringUtils.isEmpty(name)){
return name;
}
Class<?> clazz = instance.getClass();
//判断类上是否有首字母大写的注解
if (clazz.isAnnotationPresent(FirstLetterCapitalized.class)){
//是否是boolean实例
boolean isBooleanInstance = Boolean.class.isInstance(value);
//通过名称获得改域 如果使用了JSONField自定义域名会出现找不到的情况
Field field = FieldUtils.getField(clazz, name);
if (null != field){
//看看域上是否有忽略的注解和JSONField注解 或者有 忽略字段注解 如果有则不改变其属性名
if (field.isAnnotationPresent(Ignore.class) || field.isAnnotationPresent(JSONField.class)){
return name;
}else{
//判断下是不是布尔值 如果是切name不是以is开头的 首字母大写并在前面加上is
if (isBooleanInstance && !name.toLowerCase().startsWith("is")){
return "Is" + FieldNameUtils.firstLetterCapitalized(name);
}
//将属性名首字母大写返回
return FieldNameUtils.firstLetterCapitalized(name);
}
}
//用JSONField自定义属性名称可能会找不到域 因此忽略此报错 返回自定义的名称就行
return checkBoolean(clazz, name, isBooleanInstance);
}
return name;
}
private String checkBoolean(Class<?> clazz, String name,boolean isBooleanInstance){
if (isBooleanInstance){
//布尔值找不到域 存在2种可能1是用了JSONField注解 2 是使用了小写的is开头 如 isShow 这里的name会是show
String fieldName = "is" + FieldNameUtils.firstLetterCapitalized(name);
//所以拼装好名字之后 在尝试找一次域
Field field = FieldUtils.getField(clazz, fieldName);
//如果找到了返回 带is的
if (null != field){
return fieldName;
}
}
//如果还是获取不到证明使用的是 JSONField注解
return name;
}
}
如果要处理属性内容 则继承 ValueFilter 有时候会遇到BigDecimal 中放入数字 导致序列化之后精度丢失 比如 new BigDecimal(113.880) 序列化之后成了 113.8799999999999954525264911353588104248046875
每个单独处理很麻烦。所以设计了该方式:
package com.raiden.fastjson.filter;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.raiden.fastjson.util.FieldNameUtils;
import com.raiden.fastjson.annotation.DataToString;
import com.raiden.fastjson.annotation.FirstLetterCapitalized;
import com.raiden.fastjson.util.FieldUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.math.BigDecimal;
/**
* @创建人:Raiden
* @Descriotion:自定义BigDecimal序列化,精度值处理过滤器
* @Date:Created in 9:54 2019/6/22
* @Modified By:
*/
public class DataToStringFilter implements ValueFilter {
@Override
public Object process(Object instance, String name, Object value) {
if (null == instance || StringUtils.isEmpty(name) || null == value){
return value;
}
//判断下实例是不是BigDecimal 或者是 Double
if (value instanceof Double || value instanceof BigDecimal){
Class<?> instanceClazz = instance.getClass();
//如果存在这个注解说明类名可能被更改
if (instanceClazz.isAnnotationPresent(FirstLetterCapitalized.class)){
name = FieldNameUtils.firstLetterLowercase(name);
}
//如果是则获取该域 如果使用了JSONField自定义域名会出现找不到报错的情况
Field field = FieldUtils.getField(instanceClazz, name);
if (null == field){
field = getField(instanceClazz, name);
}
//检查该域是否有 DataToString注解
if (null != field && field.isAnnotationPresent(DataToString.class)){
return valueFormat(value, field);
}
}
return value;
}
/**
* 属性格式化
* @param value
* @param field
* @return
*/
private Object valueFormat(Object value,Field field){
//获取DataToString注解
DataToString dataToString = field.getAnnotation(DataToString.class);
//获取保留小数位
int newScale = dataToString.newScale();
//获取舍入策略
int roundingMode = dataToString.roundingMode();
if (value instanceof Double){
return new BigDecimal((Double) value).setScale(newScale, roundingMode).toString();
}
//返回保留值
return ((BigDecimal) value).setScale(newScale, roundingMode).toString();
}
/**
* 获取真正的属性
* @param instanceClazz
* @param name
* @return
*/
private Field getField(Class<?> instanceClazz,String name){
Class<?> superclass = instanceClazz.getSuperclass();
if (null == superclass){
//父类为空证明该类为Object 不递归了返回吧
return null;
}
//遍历全部的域
Field[] fields = instanceClazz.getDeclaredFields();
for (Field field : fields){
if (!field.isAnnotationPresent(JSONField.class)){
continue;
}
JSONField jsonField = field.getAnnotation(JSONField.class);
if (name.equals(jsonField.name())){return field;
}
}
return getField(superclass, name);
}
}
属性名称工具类:
package com.raiden.fastjson;
/**
* @创建人:Raiden
* @Descriotion: 属性名称工具类
* @Date:Created in 21:26 2019/6/23
* @Modified By:
*/
public class FieldNameUtils {
/**
* 首字母大写的方法
* @param name
* @return
*/
public static String firstLetterCapitalized(String name){
char[] chars = name.toCharArray();
StringBuilder builder = new StringBuilder();
char c = chars[0];
//如果是小写才替换
if (c > 96 && c < 123){
c -= 32;
chars[0] = c;
}
builder.append(chars);
return builder.toString();
}
/**
* 首字母小写
* @param name
* @return
*/
public static String firstLetterLowercase(String name){
char[] chars = name.toCharArray();
StringBuilder builder = new StringBuilder();
char c = chars[0];
//如果是小写才替换
if (c > 64 && c < 91){
c += 32;
chars[0] = c;
}
builder.append(chars);
return builder.toString();
}
}
package com.raiden.fastjson.util;
import java.lang.reflect.Field;
/**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 23:11 2019/7/4
* @Modified By:
*/
public class FieldUtils {
/**
* 递归获取域 子类找不到找父类 直到直到或者 递归到Object为止
* @param clazz
* @param fieldName
* @return
*/
public static Field getField(Class<?> clazz, String fieldName){
//获取父类class
Class<?> superclass = clazz.getSuperclass();
if (null == superclass){
//父类为空证明该类为Object 不递归了返回吧
return null;
}
Field declaredField = null;
try {
//忽略报错
declaredField = clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
//此处忽略报错 递归查找
return getField(superclass, fieldName);
}
//找到了返回
return declaredField;
}
}
下面是注解部分
package com.raiden.annotation;
import java.lang.annotation.*;
/**
* 该注解的作用是让FastJson序列化的时候 将所有熟悉的首字母大写
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FirstLetterCapitalized {
}
package com.raiden.annotation;
import java.lang.annotation.*;
import java.math.BigDecimal;
/**
* 用于解决BigDecimal序列化精度问题
* 将BigDecimal转成String
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DataToString {
//默认保留3位小数
int newScale() default 3;
//默认使用四舍五入
int roundingMode() default BigDecimal.ROUND_HALF_UP;
}
package com.raiden.annotation;
import java.lang.annotation.*;
/**
* 忽略该属性注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Ignore {
}
测试代码:
package com.raiden.controller;
import com.raiden.model.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
@RestController
public class UserController {
@GetMapping("getUser")
public User getUser(){
User user = new User();
user.setId("1");
user.setName("zhangsan");
user.setAge(new BigDecimal(113.880));
return user;
}
}
package com.raiden.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.raiden.annotation.DataToString;
import com.raiden.annotation.FirstLetterCapitalized;
import com.raiden.annotation.Ignore;
import com.raiden.annotation.Range;
import java.math.BigDecimal;
@FirstLetterCapitalized
public class User {
@Ignore
private String name;
@DataToString(newScale = 3,roundingMode = BigDecimal.ROUND_HALF_UP)
private BigDecimal age;
@JSONField(name = "userId")
private String id;
private boolean girl;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public BigDecimal getAge() {
return age;
}
public void setAge(BigDecimal age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGirl() {
return girl;
}
public void setGirl(boolean girl) {
this.girl = girl;
}
}
package com.raiden;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] arg){
SpringApplication.run(App.class, arg);
}
}
第一次写博客,有什么问题还望大佬们指正。代码多次修改如果跑不起来 可以去GitHub下载代码。谢谢
附上github连接:https://github.com/RaidenXin/FastJsonDemo/tree/master
关于如何在SpringMVC中为特定类自定义JSON和springmvc自定义参数解析的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于19. SpringBoot 扩展 SpringMVC功能、 接管、自定义SpringMVC、blob类型数据如何在springmvc中获取显示、json – 在Spring 3 MVC下的Jackson自定义序列化、Spring MVC中使用FastJson自定义注解的相关信息,请在本站寻找。
本文标签: