When sending a Post request using Swagger-UI, I get an empty object - spring-mvc

I am sending a Post request from the page http://localhost:9003/swagger-ui.html
Here I get this request sent using Swagger-UI
#Slf4j
#RestController
#RequestMapping("/api/book")
public class BookController {
#PostMapping("/create")
#ResponseStatus(HttpStatus.CREATED)
public Book postBook(#NotNull #Valid #RequestBody final Book book) {
log.info("Book request data {}", book );
return "Create book";
}
}
As a result of executing the postBook method, I get an empty object
Book request data(id=0, title=null, author=null)
Class Book
#Getter
#Setter
#ToString
#EqualsAndHashCode
public class Book {
private long id;
#NotBlank
#Size(min = 0, max = 20)
private String title;
#NotBlank
#Size(min = 0, max = 30)
private String author;
}
File pom.xml with Swagger and openapi dependencies enabled
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ru.main</groupId>
<artifactId>gw</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gw</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>14</java.version>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
<postgres.version>42.2.19</postgres.version>
<hibernate-core.version>5.6.2.Final</hibernate-core.version>
<jwt.version>3.13.0</jwt.version>
<lombok.version>1.18.22</lombok.version>
<openapi.version>1.6.2</openapi.version>
<fasterxml.jackson.dataformat.version>2.11.4</fasterxml.jackson.dataformat.version>
<swagger.core.version>2.1.10</swagger.core.version>
<common.version>1.0-SNAPSHOT</common.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Swagger Core -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>${openapi.version}</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.core.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>${fasterxml.jackson.dataformat.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${fasterxml.jackson.dataformat.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${fasterxml.jackson.dataformat.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${fasterxml.jackson.dataformat.version}</version>
</dependency>
</dependencies>
</project>
I don't understand what the problem might be. Error when converting from json format.
The jackson dependency is connected to my project. What else is missing?
Here's what the browser console shows (F12 -> network -> request -> payload)
{id: 0, title: "string", author: "string"}
author: "string"
id: 0
title: "string"

Related

Spring Security 6 and JSP view rendering

I'm upgrading an application from Spring Boot 2.7 to Spring Boot 3 which includes updating to Spring Security 6.
We have the following properties set:
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
We use JSPs as a template language, where the controller returns the view file name e.g.
#RequestMapping("/")
public String home() {
return "home";
}
This will render the JSP page /WEB-INF/view/home.jsp
The security config is e.g.
#Configuration
public class SecurityConfig {
#Bean
public SecurityFilterChain config(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((auth) -> auth
.requestMatchers("/").permitAll()
.anyRequest().authenticated()
);
}
Since upgrading, visiting localhost/ redirects the browser to localhost/WEB-INF/view/home.jsp and this returns a 403 because access to that page isn't permitted.
If I allow access to this with .requestMatchers("/", "/WEB-INF/**").permitAll() it works OK (i.e. stays on / and renders the JSP page) but this seems like a bad idea, and an unnecessary step.
With debug logging on, Spring logs the following:
DEBUG [requestURL=/] o.s.security.web.FilterChainProxy : Securing GET /
DEBUG [requestURL=/] o.s.security.web.FilterChainProxy : Secured GET /
DEBUG [requestURL=/] o.s.security.web.FilterChainProxy : Securing GET /WEB-INF/view/home.jsp
DEBUG [requestURL=/] o.s.security.web.FilterChainProxy : Secured GET /WEB-INF/view/home.jsp
I cant' see anything in Spring Security migration guide about this, does anyone know what is going on?
Update
I've isolated this into a clean example:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>jsptest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jsptest</name>
<packaging>war</packaging>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Application.java
#SpringBootApplication
#Controller
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public SecurityFilterChain config(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/", "/WEB-INF/view/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
#RequestMapping("/")
public String home() {
return "home";
}
}
src/main/resources/application.properties:
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
src/main/webapp/WEB-INF/view/home.jsp:
hello
Something I've overlooked first as well.
In spring security 6, forwards and includes are part of the security filter by default.
See https://docs.spring.io/spring-security/reference/5.8.0/migration/servlet/authorization.html#_permit_forward_when_using_spring_mvc
Allowing forwards globally can be done through this additional line in security configuration.
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()

Newb pact JVM provider

Hope someone might be able to help me, been beating my head against the wall for a while and can't seem to break through. I have tried following multiple examples and doing endless searching, just can't seem to find out what I am missing. There are a lot of examples to follow but most are spring applications and I know nothing about spring so I don't know if I am trying to mix spring with non-spring code...
This is NOT a spring application nor do I want it to be. I am trying to get this going as just a simple java producer verification. Pretty much as simple as it can be...
I have a good contract and I am able to get a successful verification of the contract using JS but want to use JAVA.
I have way too many imports in my code but don't know at this point which ones are not important and or are duplications.
I have a few compile errors but can't seem to find out how to resolve. I noted the compile errors in the code. I think I am close but just don't know at this point.
Is the pactTestTemplate method the one that actually does the contract verification? So that is the method I would call from my unit test? Really confused at this point as to all the magic that is going on in the background...
If you made it this far, thanks...
package testWorkContract;
import au.com.dius.pact.provider.junit.PactRunner;
import au.com.dius.pact.provider.junit.Provider;
import au.com.dius.pact.provider.junit5.*;
import au.com.dius.pact.provider.junit5.PactVerificationContext;
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider;
import org.junit.jupiter.api.extension.*;
import org.junit.runner.RunWith;
import au.com.dius.pact.provider.junit.loader.PactFolder;
import au.com.dius.pact.provider.junit.loader.PactUrl;
import au.com.dius.pact.provider.junit.target.HttpTarget;
import au.com.dius.pact.provider.junit.target.Target;
import au.com.dius.pact.provider.junit.target.TestTarget;
import org.apache.http.HttpRequest;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.runner.RunWith;
import au.com.dius.pact.provider.junit.*;
#PactFolder("/temp/pacts")
#RunWith(PactRunner.class) // Say JUnit to run tests with custom Runner
#Provider("work") // Set up name of tested provider
public class PactProvider {
#TestTarget // Annotation denotes Target that will be used for tests
public final HttpsTestTarget target = new HttpsTestTarget("127.0.0.1", 443);
#BeforeClass // Method will be run once: before whole contract test suite
public static void setUpService() {
}
#Before // Method will be run before each test of interaction
public void before() {
}
// JUST A QUICK TEST METHOD TO MAKE SURE MY UNIT TEST CAN WORK...
public int testService() {
return 0;
}
#TestTemplate // THIS IS AN ERROR, CAN'T FIND #TestTemplate
#ExtendWith(PactVerificationInvocationContextProvider.class)
void pactTestTemplate(PactVerificationContext context, HttpRequest request) {
context.verifyInteraction();
}
}
Here are my dependencies, first time setting up maven also so there might be problems there:
<properties>
<json-schema-validator.version>3.3.0</json-schema-validator.version>
<junit.jupiter.version>5.5.2</junit.jupiter.version>
<pact.version>4.0.10</pact.version>
<maven.surefire.version>3.0.0-M5</maven.surefire.version>
</properties>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.3.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-consumer-junit5</artifactId>
<version>${pact.version}</version>
</dependency>
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-junit</artifactId>
<version>${pact.version}</version>
</dependency>
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-junit5</artifactId>
<version>${pact.version}</version>
</dependency>
</dependencies>
I was able to get past my problems. I was thinking about this incorrectly. The code I was trying to write SHOULD HAVE BEEN THE ACTUAL JUNIT test. I was trying to write a junit test that then called the class I was trying to put together.
This is the junit test I ended up with for starters
package testWorkContract;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith;
import org.testng.annotations.Test;
//import au.com.dius.pact.core.model.annotations.PactFolder;
import au.com.dius.pact.provider.junit.loader.PactFolder;
import au.com.dius.pact.provider.junit.Provider;
import au.com.dius.pact.provider.junit.loader.PactSource;
import au.com.dius.pact.provider.junit5.HttpsTestTarget;
import au.com.dius.pact.provider.junit5.PactVerificationContext;
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider;
import junit.framework.Assert;
#Provider("work")
#PactFolder("/temp/pacts")
public class PactProviderTest {
#BeforeEach
void before(PactVerificationContext context) {
// context.setTarget(HttpTestTarget.fromUrl(new URL(myProviderUrl)));
// or something like
context.setTarget(new HttpsTestTarget("localhost", 443, "/", true));
}
#Test
#TestTemplate
#ExtendWith(PactVerificationInvocationContextProvider.class)
void pactVerificationTestTemplate(PactVerificationContext context) {
context.verifyInteraction();
}
}
and this is the pom file
<properties>
<json-schema-validator.version>3.3.0</json-schema-validator.version>
<junit.jupiter.version>5.5.2</junit.jupiter.version>
<pact.version>4.0.10</pact.version>
<maven.surefire.version>3.0.0-M5</maven.surefire.version>
</properties>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.3.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-consumer-junit5</artifactId>
<version>${pact.version}</version>
</dependency>
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-junit</artifactId>
<version>${pact.version}</version>
</dependency>
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-junit5</artifactId>
<version>${pact.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
<plugin>
<groupId>au.com.dius.pact.provider</groupId>
<artifactId>maven</artifactId>
<version>4.1.11</version>
<configuration>
<serviceProviders>
<!-- You can define as many as you need, but each must have a unique name -->
<serviceProvider>
<name>work</name>
<!-- All the provider properties are optional, and have sensible defaults (shown below) -->
<protocol>https</protocol>
<host>localhost</host>
<port>443</port>
<path>/</path>
<insecure>true</insecure>
<pactFileDirectories>
<pactFileDirectory>/temp/pacts</pactFileDirectory>
</pactFileDirectories>
</serviceProvider>
</serviceProviders>
</configuration>
</plugin>
</plugins>
</build>

Controller class is not getting provoked in Spring MVC

Spring MVC Controller class is not working and throwing 404.
In application I created an entity and added all the credentials of my MS-SQL database. However, after staring the app and hitting the submit button the app is landed to 404 and controller is not provoked and entity is not created as well.
index.jsp is as follows:
<form action = "/save" method = "post">
ID: <input type = "text" name = "uid">
<br />
Name: <input type = "text" name = "name" />
<input type = "submit" value = "Submit" />
</form>
Controller class is as follows:
#Controller
public class MyController {
#Autowired
public EmployeeDao empDao;
#RequestMapping("/save")
#ResponseBody
public String save(Employee emp){
System.out.println("Here");
empDao.saveEmployee(emp);
return "success";
}
}
The Entity Class:
Entity
#Table(name="employee")
public class Employee {
#Id
private int uid;
private String name;
}
The context class:
#Bean
public DriverManagerDataSource getDataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
ds.setUrl("jdbc:sqlserver://localhost:1433;databasename=cruddb11;integratedsecurity=true");
ds.setUsername("ABCD");
ds.setPassword("00000");
return ds;
}
The Pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.websparrow</groupId>
<artifactId>spring-mvc-fetch-data</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- Hibernate Core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.17.Final</version>
</dependency>
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Alpha5</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.0.2.Final</version>
</dependency>
<!-- spring mvc dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- spring jdbc dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.2.2.jre8</version>
</dependency>
<!-- mysql databse connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
This will not work as you expect.
1.) This is not neccessary but helpful if you have more than one leading part in your url. Annotate your class with the #RequestMapping Annotation. Like this:
#RequestMapping(value="/fileoperations") // Then you don't need the leading slash in the method
#Scope(value="session")
Use the second line if you are using sessions e.g. with Tomcat.
2.) The form only contains the variables uid and name so you must query them as parameters to work with in your controller.
3.) And also you must tell your controller to use the right Requestmethod. Like this:
#RequestMapping(value="save", method=RequestMethod.POST)
public #ResponseBody String save(
#RequestParam String uid,
#RequestParam String name) {
System.out.println("Here");
// Maybe you should load the Employee first before updating it.
Employee emp = this.empDao.readEmployee(name);
if (emp != null) {
emp.setUID(uid);
emp.setName(name);
this.empDao.saveEmployee(emp);
return "success";
} else {
return "error: no employee here by that name";
}
}
Change your save method signature to following, annotating Employee parameter with #ModelAttribute
#Autowired
public EmployeeDao empDao;
#RequestMapping("/save")
#ResponseBody
public String save(#ModelAttribute Employee emp){
System.out.println("Here");
empDao.saveEmployee(emp);
return "success";
}
You had better change #RequestMapping to #Post.

Spring #SqlGroup MetaAnnotation not working

I'm trying to set up a meta-annotation for some integration tests. This test works fine.
#Test
#SqlGroup( {
#Sql(scripts = {"classpath:test/sql/customers/customers.sql",
"classpath:test/sql/orders/order_addresses.sql",
"classpath:test/sql/orders/order_contact_info.sql",
"classpath:test/sql/orders/orders.sql",
"classpath:test/sql/resetKeys.sql"}),
#Sql(scripts = {"classpath:test/sql/orders/delete_orders.sql",
"classpath:test/sql/customers/delete_customers.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
})
public void testAddItemToOrder() throws Exception {
logger.entry();
Order order = orderService.findById(6l);
Assert.assertNotNull(order);
Assert.assertTrue(order.getOrderItems().isEmpty());
OrderItem orderItem = new OrderItem();
logger.exit();
}
Then I tried creating a meta-annotation interface:
#Target(ElementType.METHOD)
#SqlGroup( {
#Sql(scripts = {"classpath:test/sql/customers/customers.sql",
"classpath:test/sql/orders/order_addresses.sql",
"classpath:test/sql/orders/order_contact_info.sql",
"classpath:test/sql/orders/orders.sql",
"classpath:test/sql/resetKeys.sql"}),
#Sql(scripts = {"classpath:test/sql/orders/delete_orders.sql",
"classpath:test/sql/customers/delete_customers.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
})
public #interface SqlOrders {
}
But when I run the same method with the annotation replacing the SqlGroup, it fails because the sql data isn't loaded.
#Test
#SqlOrders
public void testAddItemToOrder() throws Exception {
logger.entry();
Order order = orderService.findById(6l);
Assert.assertNotNull(order);
Assert.assertTrue(order.getOrderItems().isEmpty());
OrderItem orderItem = new OrderItem();
logger.exit();
}
The relevant part of pom.xml follows, and spring.version is 4.2.1.RELEASE.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
Does anyone know why the data isn't being loaded with the meta-annotation version?
Your #SqlOrders annotation has no #Retention and the default is RetentionPolicy.CLASS so your annotation cannot be found by Spring at runtime.
Add #Retention(RetentionPolicy.RUNTIME) and it should work.
You can also debug SqlScriptsTestExecutionListener to find out what Spring does with your annotation.

Spring RESTful Service

I am unable to hit a Spring rest service I have created. I am new to spring and have been trying to follow the tutorials and find examples online. I am unable to determine what I am doing incorrectly.
Web.xml
<web-app>
<display-name>Friend List</display-name>
<servlet>
<servlet-name>friendlist</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>friendlist</servlet-name>
<url-pattern>/friend-list/*</url-pattern>
</servlet-mapping>
</web-app>
friend-list-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="demo.model"/>
</beans>
HelloWorld.java
package demo.model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HelloWorld {
public HelloWorld() {}
#RequestMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
I am trying to return just the text, not a view, which is the reason I have used a #RestController. I am running Java JDK 7, Eclipse Luna, and Tomcat 7. I have tried hitting localhost:8080/friend-list/hello and get a 404. Also, I have inserted a #RequestMapping("/friend-list") above the header of the class and also received 404s going to both /friend-list/hello and /friend-list/friend-list/hello.
Tomcat Log:
INFO: Mapped URL path [/hello] onto handler 'helloWorld'
Jul 23, 2014 8:20:35 PM org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping registerHandler
INFO: Mapped URL path [/hello.*] onto handler 'helloWorld'
Jul 23, 2014 8:20:35 PM org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping registerHandler
INFO: Mapped URL path [/hello/] onto handler 'helloWorld'
POM.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo</groupId>
<artifactId>friend-list</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>friend-list Maven Webapp</name>
<url>http://maven.apache.org</url>
<build>
<finalName>friend-list</finalName>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.0.5</version>
<exclusions>
<exclusion>
<artifactId>jta</artifactId>
<groupId>javax.transaction</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
</dependencies>
</project>
Any assistance would be appreciated.
Couple of things:
*You need to update your web.xml: (hyphen is important with the servlet name)
<servlet>
<servlet-name>friend-list</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>friend-list</servlet-name>
<url-pattern>/friend-list/*</url-pattern>
</servlet-mapping>
*For Hello World you are missing a few things.
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
#Controller
#RequestMapping("/hello")
public class HelloWorld {
public HelloWorld() {
}
#RequestMapping(method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public String hello() {
return "Hello, World!";
}
}
RequestMapping for the Resource then you are going to want to map the resource methods.
ResponseBody was missing as well
*Once your app is up and running you should be able to hit:
localhost:8080/myapp/friend-list/hello
Where myapp is whatever you named your app.
I like using postman ( Chrome plugin and easy to us.)
*http://spring.io/guides/tutorials/rest/2/ Excellent tutorial in regards to Spring and REST.
Spring wasn't loading your #RestController because the spring configuration file was not having a filename that matched the name of your servlet. So if your servlet name in Web.xml is friendlist, then your spring configuration file should be named friendlist-servlet.xml

Resources