带有 Spring Boot REST 控制器和 JSON 的空字段

Posted

技术标签:

【中文标题】带有 Spring Boot REST 控制器和 JSON 的空字段【英文标题】:null fields with Spring Boot REST controller and JSON 【发布时间】:2015-01-28 22:53:27 【问题描述】:

我有一个带有这个 Gradle 构建文件的 Spring Boot 应用程序:

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'
apply plugin: 'war'

sourceCompatibility = 1.7
targetCompatibility = 1.7

version = '1.0'

buildscript 
    ext 
        springBootVersion = '1.1.9.RELEASE'
    
    repositories 
        maven  url "http://repo.spring.io/libs-snapshot" 
        mavenLocal()
    
    dependencies 
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.9.RELEASE")
    


jar 
    manifest 
        attributes 'Implementation-Title': 'Server', 'Implementation-Version': version
    


war 
    baseName = 'gs-convert-jar-to-war'
    version =  '0.1.0'


repositories 
    mavenCentral()
    maven  url "http://repo.spring.io/libs-snapshot" 
    maven  url "http://maven.springframework.org/milestone" 


dependencies 
    compile("org.springframework.boot:spring-boot-starter-web:$springBootVersion")

    compile("org.springframework.boot:spring-boot-starter-tomcat:$springBootVersion")

    compile("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-aop:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-test:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-security:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion")

    compile("org.springframework.data:spring-data-rest-webmvc")

    compile("org.hsqldb:hsqldb")

    compile("com.google.guava:guava:17.0")
    compile("org.apache.httpcomponents:httpclient:4.3.4")
    compile("commons-io:commons-io:2.4")

    testCompile("junit:junit")

使用此应用程序文件:

@EnableAutoConfiguration
@Configuration
@ComponentScan
@Import( BasicSecurityConfiguration.class, HTTPSTomcatConfiguration.class,
        MultiPartConfiguration.class )
public class Application extends RepositoryRestMvcConfiguration 

    public static void main(String[] args) 
        SpringApplication.run(Application.class, args);
    

    // use JSON
    @Override
    public ObjectMapper halObjectMapper() 
        return new ResourcesMapper();
    


这个配置文件:

@Configuration
@EnableWebSecurity
public class BasicSecurityConfiguration extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        // no cache
        http.requestCache().requestCache(new NullRequestCache());

        // use HTTPS
        http.requiresChannel().anyRequest().requiresSecure();
        http.portMapper().http(8080).mapsTo(8443);

        // this replaces the web security http configuration
        http.authorizeRequests().antMatchers("/**").authenticated().and()
                .httpBasic();

        // disable CSRF
        http.csrf().disable();
    

    @Autowired
    protected void registerAuthentication(
            final AuthenticationManagerBuilder auth) throws Exception 

        // FIXME create a full user registry
        // in-memory users
        auth.inMemoryAuthentication().withUser("admin").password("pass")
                .authorities("admin", "user").and().withUser("user")
                .password("pass").authorities("user");
    


@Configuration
public class HTTPSTomcatConfiguration 
    @Bean
    EmbeddedServletContainerCustomizer containerCustomizer(
            @Value("8443") final int port,
            @Value("keystore.p12") Resource keystoreFile,
            @Value("tomcat") final String alias,
            @Value("localhost") final String keystorePass,
            @Value("PKCS12") final String keystoreType) throws Exception 

        final String absoluteKeystoreFile = keystoreFile.getFile()
                .getAbsolutePath();

        return new EmbeddedServletContainerCustomizer() 
            public void customize(ConfigurableEmbeddedServletContainer container) 
                TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;
                tomcat.addConnectorCustomizers(new TomcatConnectorCustomizer() 
                    public void customize(Connector connector) 
                        connector.setPort(port);
                        connector.setSecure(true);
                        connector.setScheme("https");
                        Http11NioProtocol proto = (Http11NioProtocol) connector
                                .getProtocolHandler();
                        proto.setSSLEnabled(true);
                        proto.setKeystoreFile(absoluteKeystoreFile);
                        proto.setKeyAlias(alias);
                        proto.setKeystorePass(keystorePass);
                        proto.setKeystoreType(keystoreType);
                    
                );
            
        ;
    

@Configuration
@EnableConfigurationProperties(MultipartProperties.class)
public class MultiPartConfiguration 

    @Bean
    public MultipartConfigElement multipartConfigElement() 
        return new MultipartConfigElement("");
    


这个控制器接口:

public interface Controller 

    @RequestMapping(value = "/t", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Test t(@RequestBody Test test);


还有这个控制器实现:

@RestController
public class ControllerImpl implements Controller 

    @Override
    public Test t(Test test) 
        return test;
    

似乎一切正常,除了从客户端到服务器的 JSON 序列化。当我执行这个curl 命令时:

curl --insecure -H "Authorization: Basic YWRtaW46cGFzcw==" -H "Content-Type: application/json" -X POST -d '"a":"a","b":"b"' https://localhost:8443/t

我明白了:

"a":null,"b":null

如果我只在控制器实现中进行调试,我会看到字段为null。如果我这样修改控制器:

@Override
public Test t(Test test) 
    Test t = new Test();
    t.setA("a");
    t.setB("b");
    return t;

我得到正确答案:

"a":"a","b":"b"

为什么我的应用没有正确反序列化 Test 对象?

【问题讨论】:

【参考方案1】:

您的接口中有@RequestBody 注释,您需要在方法实现中使用它:

@RestController 
public class ControllerImpl implements Controller 

    @Override
    public Test t(@RequestBody Test test) 
        return test;
    

【讨论】:

接口和实现类都需要注解吗?我会在几个小时后尝试。 只在实现时需要

以上是关于带有 Spring Boot REST 控制器和 JSON 的空字段的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2 + CORS + 带有 Spring Security 的 Spring Boot Rest Controller

使用带有 Spring Boot 的 Spock 测试框架来测试我的 REST 控制器

尝试在外部在tomcat 9上运行带有rest控制器的spring boot war文件

REST 控制器中的 Spring Boot 绑定和验证错误处理

在同一个 Spring Boot 应用程序中的 Rest 服务和 Web 服务

带有 Spring Boot 的 JSON 和 HTML 控制器