0

I am creating a simple web service using Spring 3 with Hibernate 5.

My maven dependencies for those are:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>3.2.14.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>3.2.14.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.0.1.Final</version>
        </dependency>

This isn't my full dependency list but it gives a good idea of the versions I'm using.

The basic requirements of this web service are to provide an endpoint by which a user can request some data based on a unique ID. The data has to be returned as JSON. The data is being retrieved from a SQL Server 2008 database view.

I have successfully configured the web service to use Hibernate and JPA to get the correct data where an ID is matched on a row in the view. The ID is provided as a parameter with the URL, for example:

http://some/resource/location.json?id=1234

Now as I said, this works fine, gets the data if the ID is matched and returns a POJO marshalled as json to the user.

My issue is the requirement to include the '.json' file extension as part of the URL. Ideally I would like the URL to look something like this instead:

http://some/resource/location?id=1234

Notice no '.json'

The view resolver I am using is configured as follows, just ignore the xml stuff, I have that in there because I will need it further down the line:

    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1"/>
        <property name="contentNegotiationManager">
            <bean class="org.springframework.web.accept.ContentNegotiationManager">
                <constructor-arg>
                    <bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
                        <constructor-arg>
                            <map>
                                <entry key="json" value="application/json"/>
                                <entry key="xml" value="application/xml"/>
                            </map>
                        </constructor-arg>
                    </bean>
                </constructor-arg>
            </bean>
        </property>
        <property name="defaultViews">
            <list>
                <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
                <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <constructor-arg>
                        <bean class="org.springframework.oxm.xstream.XStreamMarshaller">
                            <property name="autodetectAnnotations" value="true"/>
                        </bean>
                    </constructor-arg>
                </bean>
            </list>
        </property>
    </bean>

Is there a different view resolver I should implement maybe?

I can include more detail if needed, just ask, thanks for any help on this.

Jeremy
  • 3,418
  • 2
  • 32
  • 42

2 Answers2

1

check this spring.io tutorial. it will fit in your needs and more specially this xml config, because i see that you use xml config instead of java config:

 <!-- Total customization - see below for explanation. -->
  <bean id="contentNegotiationManager"
             class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="true" />
    <property name="favorParameter" value="false" />
    <property name="parameterName" value="mediaType" />
    <property name="ignoreAcceptHeader" value="true"/>
    <property name="useJaf" value="false"/>
    <property name="defaultContentType" value="application/json" />

    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
       </map>
    </property>
</bean>

I think I customise it for your needs.

Nikolay Rusev
  • 4,060
  • 3
  • 19
  • 29
  • 1
    OK so I +1 your answer but it wasn't quite so cut and dry as I'd hoped from the tutorial you linked. I did however get to the answer eventually by extracting a small simplified section of it out, which I will detail here next. – Jeremy Dec 02 '15 at 15:06
0

Nikolay pointed me in the right direction, but the actual answer was such a small section of that tutorial I thought it would be more helpful to others looking for similar answers to show exactly what solution I used in the end here.

Basically the key was to add a produces = {"application/json"} param to my controller method that I mapped to a URl, like so:

    @RequestMapping(
            value = "/some/resource/location",
            method = RequestMethod.GET,
            produces = {"application/json"}
    )
    public @ResponseBody CustomClass getSomething(@RequestParam String id) {
        return customService.getSomethingById(id);
    }

Plus I had to be quite specific with my servlet URL mapping, moving away from mapping by extension to mapping by specific URI. I'm sure this could be done differently but it worked for my specific requirements:

<servlet>
    <servlet-name>myServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/config/servlet-config.xml</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>myServlet</servlet-name>
    <url-pattern>/some/resource/location</url-pattern>
</servlet-mapping>

I should note that I got some help with the servlet url pattern configuration from another stack overflow answer discussing what values the url pattern would except.

And that's it, it just worked, no need to include a special content negotiator bean after all.

I simply use the end point like this:

http://some/resource/location?id=1234

And it returns json.

Community
  • 1
  • 1
Jeremy
  • 3,418
  • 2
  • 32
  • 42