Why web service and proxy client not connecting? - java

I have an application where I try to combine Spring MVC and Apache CFX(soap) web services. When I run just the app, everything seems fine, I see generated WSDL by this link(http://localhost:8080/services/customer?wsdl). But when I run tests, it throws WebServiceException: Could not send Message... Connection refused.
I've opened all ports for public, private and domain area through Windows Firewall Defender. Maybe I've missed something.
In a desperate attempt to investigate it, I've checked the link with this command (wsimport -keep -verbose http://localhost:8080/services/customer?wsdl). As a result, it gave this:
[ERROR] Server returned HTTP response code: 403 for URL: http://localhost:8080/services/customer?wsdl
Failed to read the WSDL document: http://localhost:8080/services/customer?wsdl, because 1) could not find the document; /2) the document could not be read; 3) the root element of the document is not <wsdl:definitions>.
[ERROR] Could not find wsdl:service in the provided WSDL(s):
At least one WSDL with at least one service definition needs to be provided.
Now I do not know which way to dig.
WebServiceDispatcherServletInitializer
public class WebServiceDispatcherServletInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebServiceConfig.class);
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new CXFServlet());
dispatcher.addMapping("/services/*");
}
}
WebServiceConfig
#Configuration
public class WebServiceConfig {
#Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), new CustomerWebServiceImpl() );
endpoint.publish("http://localhost:8080/services/customer");
return endpoint;
}
}
ClientConfig
#Configuration
public class ClientConfig {
#Bean(name = "client")
public Object generateProxy() {
return proxyFactoryBean().create();
}
#Bean
public JaxWsProxyFactoryBean proxyFactoryBean() {
JaxWsProxyFactoryBean proxyFactory = new JaxWsProxyFactoryBean();
proxyFactory.setServiceClass(CustomerWebService.class);
proxyFactory.setAddress("http://localhost:8080/services/customer");
return proxyFactory;
}
}
CustomerWebServiceImplTest
#ActiveProfiles(profiles = "test")
#ContextConfiguration(classes = {
PersistenceConfig.class,
RootConfig.class,
WebServiceConfig.class,
ClientConfig.class
})
#WebAppConfiguration
public class CustomerWebServiceImplTest {
private ApplicationContext context = new AnnotationConfigApplicationContext(ClientConfig.class);
private CustomerWebService customerWsProxy = (CustomerWebService) context.getBean("client");
#Test
public void addCustomer() {
CustomerDto customer = new CustomerDto();
customer.setName("John");
assertEquals("Hello " + customer.getName(), customerWsProxy.addCustomer(customer));
}
}
Could you give a hint where the error might be?
UPD: I checked this setup on PC where I and my applications have full access rights and it still throws the Exception.

A solution was quite simple - just need to add #RunWith(SpringRunner.class). Because this annotation is run spring beans, not #WebAppConfiguration with #ContextConfiguration.
This is how it will look like
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {
RootConfig.class,
WebServiceConfig.class,
ClientConfig.class
})
public class CustomerWebServiceImplTest {
...
}

Related

How to set urls with port of StubRunner from spring-cloud-contract in spring-cloud-gateway contract tests

I have a spring cloud gateway application which routes requests to another service. Another service defines contracts which are imported as stubs by spring cloud gateway application in tests.
Now I would like to have contract tests in my gateway that will consume the stubs of another service. The problem is that I do not know how to inject the StubRunnerPort as property/environment so it can be picked by my configuration class and configure the routes accordingly :
Api gateway routes configuration
#Configuration
class GatewayConfig {
#Value("${subscriptions.url}")
private String subscriptionsUrl;
#Autowired
private TokenRelayGatewayFilterFactory tokenFilterFactory;
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.csrf(ServerHttpSecurity.CsrfSpec::disable);
return http.build();
}
#Bean
RouteLocator routeLocator(final RouteLocatorBuilder routeLocatorBuilder) {
return routeLocatorBuilder.routes()
.route("subscriptions", subscriptionsRoute())
.build();
}
private Function<PredicateSpec, Buildable<Route>> subscriptionsRoute() {
return spec -> spec
.path("/subscriptions/**")
.filters(s -> s.filter(tokenFilterFactory.apply()).prefixPath("/v1"))
.uri(subscriptionsUrl);
}
}
And the test class :
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {PnApiGatewayApp.class})
#AutoConfigureStubRunner(ids = "io.mkrzywanski:subscription-app:+:stubs", stubsMode = StubRunnerProperties.StubsMode.CLASSPATH)
#ActiveProfiles("test")
class SubscriptionSpec {
private WebTestClient webClient;
#LocalServerPort
private int port;
#StubRunnerPort("io.mkrzywanski:subscription-app")
private int stubRunnerPort;
#Autowired
ConfigurableEnvironment environment;
#BeforeEach
void setup() {
String baseUri = "http://localhost:" + port;
this.webClient = WebTestClient.bindToServer()
.responseTimeout(Duration.ofSeconds(10))
.baseUrl(baseUri).build();
}
#Test
void test() {
String body = "{\"userId\":\"22e90bbd-7399-468a-9b76-cf050ff16c63\",\"itemSet\":[{\"value\":\" Rainbow Six\"}]}";
var response = webClient.post()
.uri("/subscriptions")
.header("Authorization", "Bearer xxx")
.header("Content-type", MediaType.APPLICATION_JSON_VALUE)
.bodyValue(body)
.exchange()
.expectStatus().isCreated()
.expectBody(String.class)
.value(Matchers.equalTo("{\"subscriptionId : \"6d692849-58fd-439b-bb2c-50a5d3669fa9\"\"}"));
}
Ideally I would like to have subscriptions.url property set after stub runner is configured but before my gateway configuration is picked by Spring so that url redirects will work.
I have already tried to use ApplicationContextInitializer but it seems that StubRunnerPort is not configured yet, when instance of initializer is launched.
So the question is - how to get stub runner port and use it to inject it into other services url, so that gateway would route the requests to the stub runner in tests?
Solution 1
This can be achieved by using application-test.yml file with defined url property that makes use of substitution. application-test.yml file. The approach is described here :
subscriptions:
url: http://localhost:${stubrunner.runningstubs.io.mkrzywanski.subscription-app.port}
Here stubrunner.runningstubs.io.mkrzywanski.subscription-app.port will be available as Stub port so it can be substituted. No configuration changes are reuqired.
Solution 2 (requires more code)
I made it work by creating a test configuration which extends configuration that contains url properties and RouteLocator configuration and has a dependency on batchStubRunner bean :
#DependsOn("batchStubRunner")
#EnableAutoConfiguration
#Import(LoggingFilter.class)
class GatewayTestConfig extends GatewayConfig implements InitializingBean {
#Autowired
ConfigurableEnvironment environment;
#Override
public void afterPropertiesSet() {
this.subscriptionsUrl = "http://localhost:" + environment.getProperty("stubrunner.runningstubs.io.mkrzywanski.subscription-app.port");
}
}
The key points here are :
the configuration is run only after batchStubRunner bean is available so the port of StrubRunner can be found in the environment
The configuration implements InitializingBean so I am able to override the subscriptionsUrl which is now protected in parent configuration
After subscriptionsUrl is overriden - it can be used to configure RouteLocator bean from parent configuration.
The test looks like this now :
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {GatewayTestConfig.class})
#AutoConfigureStubRunner(ids = "io.mkrzywanski:subscription-app:+:stubs", stubsMode = StubRunnerProperties.StubsMode.CLASSPATH)
#ActiveProfiles("test")
class SubscriptionSpec {
private WebTestClient webClient;
#LocalServerPort
private int port;
#BeforeEach
void setup() {
String baseUri = "http://localhost:" + port;
this.webClient = WebTestClient.bindToServer()
.responseTimeout(Duration.ofSeconds(10))
.baseUrl(baseUri).build();
}
#Test
void shouldRouteToSubscriptions() {
String body = "{\"userId\":\"22e90bbd-7399-468a-9b76-cf050ff16c63\",\"itemSet\":[{\"value\":\"Rainbow Six\"}]}";
webClient.post()
.uri("/subscriptions")
.header("Accept", MediaType.APPLICATION_JSON_VALUE)
.header("Authorization", "Bearer xxx")
.header("Content-type", MediaType.APPLICATION_JSON_VALUE)
.bodyValue(body)
.exchange()
.expectStatus().isCreated()
.expectBody()
.jsonPath("$.subscriptionId").exists()
.jsonPath("$.subscriptionId").value(IsUUID.UUID());
}
}

Spring Keycloak: Get User ID

I have developed a Spring Boot Webservice and use Keycloak for Access Management.
The website stores some userdata in a database. I try to connect these data with the user logged in.
At the moment I store the username with the data. But I like to store the user id instead the username. How can I do that?
I try to get SecurityContext by this:
#Bean
#Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public KeycloakSecurityContext getKeycloakSecurityContext() {
return ((KeycloakPrincipal<KeycloakSecurityContext>) getRequest().getUserPrincipal()).getKeycloakSecurityContext();
}
But I get an error:
There was an unexpected error (type=Internal Server Error, status=500).
Error creating bean with name 'scopedTarget.getKeycloakSecurityContext'
defined in com.SiteApplication: Bean instantiation via factory method
failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [org.keycloak.KeycloakSecurityContext]: Factory method
'getKeycloakSecurityContext' threw exception; nested exception is
java.lang.ClassCastException:
org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken
cannot be cast to org.keycloak.KeycloakPrincipal
Is this the right way? What is missing?
Thank you!
I found a much simpler solution than the above:
#GetMapping
public ResponseEntity getEndpoint(String someParam, HttpServletRequest request) {
KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request.getUserPrincipal();
String userId = principal.getAccount().getKeycloakSecurityContext().getIdToken().getSubject();
//....do something
return new ResponseEntity(HttpStatus.OK);
}
I think the exception you are getting above is because you are trying to cast getRequest().getUserPrincipal() to KeycloakPrincipal<KeycloakSecurityContext> while it is of type KeycloakAuthenticationToken, so ((KeycloakAuthenticationToken) getRequest().getUserPrincipal()) would work.
I've done something similar in our code.
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("Expecting a HTTP request");
}
RefreshableKeycloakSecurityContext context = (RefreshableKeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
if (context == null) {
handleNoSecurityContext(request, response, chain);
return;
}
AccessToken accessToken = context.getToken();
Integer userId = Integer.parseInt(accessToken.getOtherClaims().get("user_id").toString());
chain.doFilter(request, response);
}
}
Before you can do this you must add the user_id to the access tokens being issued by keycloak. You can do this through a mapper as shown in the screenshot below.
Also, don't forgot to add the processing filter from above to your application lifecycle by adding a #Bean method to your application class.
#Configuration
#EnableAutoConfiguration(exclude = {FallbackWebSecurityAutoConfiguration.class, SpringBootWebSecurityConfiguration.class, DataSourceAutoConfiguration.class})
#ComponentScan
#EnableAsync
public class MyServiceClass {
public static void main(String[] args) {
Properties properties = new Properties();
new SpringApplicationBuilder(MyServiceClass.class)
.properties(properties)
.bannerMode(Banner.Mode.OFF)
.run(args);
}
#Bean
public AuthenticationTokenProcessingFilter authFilter() {
return new AuthenticationTokenProcessingFilter();
}
}
All solutions above are using the (very) deprecated Keycloak Spring adapters, which was a solution 2 years ago, but isn't anymore.
2 Alternatives to Keycloak Spring adapters, both having very easy way to access-token claims from Authentication "auto-magically" injected by Spring as #Controller method parameter.
spring-addons-webmvc-jwt-resource-server
Sample here: almost everything configurable from properties
#GetMapping
#PreAuthorize("isAuthenticated()")
public ResponseEntity getEndpoint(OAuthentication<OpenidClaimSet> auth) {
final var preferredUsername = auth.getClaims().getPreferredUsername();
final var subject = auth.getClaims().getSubject();
//....do something
return new ResponseEntity(HttpStatus.OK);
}
spring-boot-starter-oauth2-resource-server
Sample there: requires much more Java config
#GetMapping
#PreAuthorize("isAuthenticated()")
public ResponseEntity getEndpoint(JwtAuthenticationToken auth) {
final var preferredUsername = auth.getToken().getClaimAsString(StandardClaimNames.SUB);
final var subject = auth.getToken().getClaimAsString(StandardClaimNames.PREFERRED_USERNAME);
//....do something
return new ResponseEntity(HttpStatus.OK);
}

Spring Boot & OAuth2: Getting ResourceAccessException: I/O error on POST request for "http://localhost:5555/oauth/token": Connection refused: connect

based on this example https://github.com/royclarkson/spring-rest-service-oauth I have modified the source code adding repositories and other rest controllers. The resource and authorization servers are running/configured in the same application.
I have added an endpoint "/api/login" (POST) with request body:
{"usernamme":"foo", "password":"bar"}
I want to get an access token for this user in the service called by the controller. This implementation looks as follows:
Controller
public ResponseEntity<OAuth2AccessToken> login(#RequestBody #Valid final LoginCommand credentials)
throws LoginFailedException, UnexpectedErrorException {
try {
final OAuth2AccessToken token = securityService.authenticate(credentials.getUsername(), credentials.getPassword());
return ResponseEntity.ok(token);
} catch (final InvalidGrantException badCredentialExeption) {
throw new LoginFailedException(badCredentialExeption.getMessage());
} catch (final Exception e) {
throw new UnexpectedErrorException(e.getMessage());
}
}
Service
#Autowired
#Qualifier("OAuth2RestOperations")
private OAuth2RestOperations client;
#Override
public OAuth2AccessToken authenticate(final String username, final String password) {
final ResourceOwnerPasswordResourceDetails resourceDetails = (ResourceOwnerPasswordResourceDetails) client.getResource();
resourceDetails.setUsername(username);
resourceDetails.setPassword(password);
return client.getAccessToken();
}
Rest client config
#Configuration
#Import({ OauthProperties2.class })
#EnableOAuth2Client
public class RestClientConfig {
#Autowired
private OauthProperties2 oauth;
#Bean(name = "OAuth2RestOperations")
public OAuth2RestOperations restTemplate(final OAuth2ClientContext oauth2ClientContext) {
return new OAuth2RestTemplate(resource(), oauth2ClientContext);
}
#Bean
public OAuth2ProtectedResourceDetails resource() {
final ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setAccessTokenUri(oauth.getClient().getAccessTokenUri());
resource.setClientId(oauth.getClient().getClientId());
resource.setClientSecret(oauth.getClient().getClientSecret());
resource.setGrantType(oauth.getClient().getGrantType());
resource.setScope(oauth.getClient().getScope());
return resource;
}
}
The Test
public class SecurityApiControllerTest extends TestBase {
#InjectMocks
private SecurityApiController controller;
#Test
public void loginOK() throws Exception {
final String credentials = FileUtils.readContent("requests/loginOK.json");
// #formatter:off
mvc.perform(post("/api/login")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(credentials))
.andExpect(status().isOk());
// #formatter:on
}
}
TestBase
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#SpringBootTest(classes = Application.class)
public class TestBase {
#Autowired
protected WebApplicationContext context;
#Autowired
protected FilterChainProxy springSecurityFilterChain;
protected MockMvc mvc;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.webAppContextSetup(context).addFilter(springSecurityFilterChain).build();
}
}
When running the application, I can call the endpoint for example with POSTMAN. During the test I get a connection refused as described in question header. I have tried to figure out the reason why the test is not working. Can anybody give me a hint to solve this issue?
It is so weird. It works since I have changed the TestBase class to:
#RunWith(SpringJUnit4ClassRunner.class)
// #WebAppConfiguration
#ContextConfiguration(classes = Application.class)
#SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)

415 Unsupported Media Type AngularJS to SpringMVC Controller

I'm getting this error when trying to post JSON data from angularjs controller to SpringMVC controller. I've tried a lot of solutions posted here and some other stuff available on the net as well. I already have the jackson library in my classpath. And also I'm not using maven because of internet issues.
SpringMVC Controller
#Controller
public class MainController {
#RequestMapping("/")
public String index() {
return "index";
}
#RequestMapping(value = "/employee", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
String saveEmployee(#RequestBody Employee employee) {
//Will do some stuff here.
System.out.println("INSIDE CONTROLLER");
StringBuilder json = new StringBuilder();
return json.toString();
}
}
AngularJS Controller
app.controller('saveEmployeeCtrl', function ($scope, $http) {
$scope.employee = {};
$scope.saveEmployee = function () {
$http({
method: 'POST',
url: 'employee',
data: $scope.employee,
headers:{'Accept':'application/json', 'Content': 'application/json'}
}).success(function(data){
console.log('something nice');
});
};
});
WebConfig
#EnableWebMvc
#Configuration
#ComponentScan("springmvc.com.")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webapp/resources/static/app/**")
.addResourceLocations("/webapp/resources/static/app/");
registry.addResourceHandler("/webapp/resources/static/lib/**")
.addResourceLocations("/webapp/resources/static/lib/");
registry.addResourceHandler("/webapp/resources/static/js/**")
.addResourceLocations("/webapp/resources/static/js/");
registry.addResourceHandler("/webapp/resources/static/css/**")
.addResourceLocations("/webapp/resources/static/css/");
registry.addResourceHandler("/webapp/webapp/resources/static/views/**")
.addResourceLocations("/webapp/webapp/resources/static/views/");
registry.addResourceHandler("/webapp/resources/static/**")
.addResourceLocations("/webapp/resources/static/");
}
#Override
public void configureContentNegotiation(
ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).favorParameter(true)
.parameterName("mediaType").ignoreAcceptHeader(true)
.useJaf(false).defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
}
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
WebAppInitializer
public class WebAppInitializer implements WebApplicationInitializer {
private static final String CONFIG_LOCATION = "springmvc.com.config";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("***** Initializing Application for " + servletContext.getServerInfo() + " *****");
// Create ApplicationContext
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.setConfigLocation(CONFIG_LOCATION);
// Add the servlet mapping manually and make it initialize automatically
DispatcherServlet dispatcherServlet = new DispatcherServlet(applicationContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("mvc-dispatcher", dispatcherServlet);
servlet.addMapping("/");
servlet.setAsyncSupported(true);
servlet.setLoadOnStartup(1);
}
}
You are sending header "Content" but you should send "Content-Type"
Do you send exactly the same fields in JSON as there are in Employee class, check if there are no additional fields, because Jackson has setting that it fail if unrecognized field is set. And there are some resolutions for this issue (like annotation on your class or change this setting)
Most important is what appear in the log file of your server application. What exception is raised as a cause of this http status. So i the solutions above not helping you, please check logs (maybe increase log level for spring) and post it here.
UPDATE:
I have few additional questions:
has your Employee class got default (non args) constructor or maybe you create only constructor with arguments? Could you post your Employee class.
Do you have any logger attached to your project, is there anything in log file, (if there is, please post it)?

Problems with controller mapping in Spring MVC

There are similar topics, but they all use xml configuration files. The reason why I'm writing this question is that I'm using annotations.
I experience problems running my app:
getting “WARN org.springframework.web.servlet.PageNotFound - No
mapping found for HTTP request with URI …” when trying to setup
Spring servlet
getting error 404 when trying to run it on server
Here is my code (package and imports are skipped):
1) initializer
public class WebInitializer implements WebApplicationInitializer{
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx =
new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet =
servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
2) app config
#Configuration
#ComponentScan("ua.kiev.prog")
#EnableWebMvc
public class AppConfig {
#Bean
public EntityManager entityManager() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("AdvJPA");
return emf.createEntityManager();
}
#Bean
public AdvDAO advDAO() {
return new AdvDAOImpl();
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
resolver.setOrder(1);
return resolver;
}
#Bean
public CommonsMultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
}
3) controller
#Controller
#RequestMapping("/Advertisement")
public class MainController {
#Autowired
private AdvDAO advDAO;
#RequestMapping("/")
public ModelAndView listAdvs() {
return new ModelAndView("index", "advs", advDAO.list());
}
#RequestMapping(value = "/add_page", method = RequestMethod.POST)
public String addPage(Model model) {
return "add_page";
}
#RequestMapping(value = "/search", method = RequestMethod.POST)
public ModelAndView search(#RequestParam(value="pattern") String pattern) {
return new ModelAndView("index", "advs", advDAO.list(pattern));
}
// more code goes here
}
The controller is mapped to /Advertisement, so app should be available at URL localhost:8080/Advertisement/ but it isn't. When I change mapping in annotation to "/" - it becomes available at localhost:8080/Advertisement/. How can it be?
And when I change it back to "/Advertisement" - the same probleb accurs (error 404 and exception "No mapping found for HTTP request with URI …")
So, where I've made a mistake in my code?
Or maybe the problem is in Eclipse/TomCat/Maven?
Source - https://github.com/KostyantynPanchenko/prog.kiev.ua.lesson09.adv
You should change mapping
#Controller
#RequestMapping("/")
public class MainController {
#Autowired
private AdvDAO advDAO;
#RequestMapping("/Advertisement")
public ModelAndView listAdvs() {
return new ModelAndView("index", "advs", advDAO.list());
}
The mistake that a mapper used the value from the annotation to match the request URL, and it can't match the last slash. Note, it should not happen in the above code.
How are you running the application? Atleast in tomcat each deployed application is served from specific context path. Context path is determined from the base file name, more on that here.
So if you're deploying Advertisement.war all requests to the app will be served from localhost:8080/Advertisement/ even though you're declaring the DispatcherServlet and Controller to /

Categories