VersionResourceResolver not working - java

I have static resources' structure like this in my spring application :
\src
\main
\webapp
\resouces
\css\..
\js\..
and have configured VersionResourceResolver like this :
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)).resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
I included the resources using jstl in my jsp:
<script type="text/javascript" src="<c:url value="/resources/js/my.js"/>"></script>
But when i run the application I cannot see any kind of versioning.
What am I missing ?
Also I have tried :
https://stackoverflow.com/a/38407644/3603806
But no luck
UPDATE
I am including resources like this :
<link rel="stylesheet" href="<c:url value="/resources/css/mycss.css?v=2" />">
<script type="text/javascript" src="<c:url value="/resources/js/myjs.js?v=1"/>"></script>
and this is what is getting generated :
<link rel="stylesheet" href="/app/resources/css/mycss.css?v=2">
<script type="text/javascript" src="/app/resources/js/myjs.js?v=1"></script>
index page using :
<welcome-file-list>
<welcome-file>/WEB-INF/views/index.jsp</welcome-file>
</welcome-file-list>
Controller : for home etc...
#RequestMapping(value = "/home", method = RequestMethod.GET)
public ModelAndView home(HttpServletRequest request, ModelMap model) {
...
}

Might be ResourceUrlProvider is null for you in encodeURL of ResourceUrlEncodingFilter.ResourceUrlEncodingResponseWrapper
#Override
public String encodeURL(String url) {
ResourceUrlProvider resourceUrlProvider = getResourceUrlProvider();
if (resourceUrlProvider == null) {
logger.debug("Request attribute exposing ResourceUrlProvider not found");
return super.encodeURL(url);
}
initIndexLookupPath(resourceUrlProvider);
if (url.length() >= this.indexLookupPath) {
String prefix = url.substring(0, this.indexLookupPath);
int suffixIndex = getQueryParamsIndex(url);
String suffix = url.substring(suffixIndex);
String lookupPath = url.substring(this.indexLookupPath, suffixIndex);
lookupPath = resourceUrlProvider.getForLookupPath(lookupPath);
if (lookupPath != null) {
return super.encodeURL(prefix + lookupPath + suffix);
}
}
return super.encodeURL(url);
}
To fix it, register ResourceUrlEncodingFilter in web.xml or in WebApplicationInitializer, as follows:
<filter>
<filter-name>resourceUrlEncodingFilter</filter-name>
<filter-class>
org.springframework.web.servlet.resource.ResourceUrlEncodingFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>resourceUrlEncodingFilter</filter-name>
<servlet-name>spring-dispatcher</servlet-name>
</filter-mapping>
where spring-dispatcher is DispatcherServlet, as:
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
And make sure your my jsp is rendered through spring-dispatcher, for example:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class HomeController {
#RequestMapping(value = "/my-jsp", method = RequestMethod.GET)
public String home() {
return "my";
}
}
I created a sample app available on GitHub - spring-resource-versioning, which can answer your further questions.
Hope it help!

I ran into same issue like 1 hour ago. I solved it by overriding this method:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
VersionResourceResolver versionResolver = new VersionResourceResolver()
.addFixedVersionStrategy(version, "/**/*.js")
.addContentVersionStrategy(version, "/**/*.css", "/**/*.png"); //adjust those paths according to the webapp's folder names
registry.addResourceHandler("/res/**")
.addResourceLocations("/resources/")
.setCachePeriod(CACHE_SECONDS)
.resourceChain(true)
.addResolver(versionResolver);
}

As Arpit Aggarwal said, you need ResourceUrlEncodingFilter that corresponds to your main DispacherServlet. But adding it in java config didn't help me.
I solved this issue by replacing
#Bean
public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
return new ResourceUrlEncodingFilter();
}
with
#Bean
public FilterRegistrationBean<?> resourceUrlEncodingFilterRegistration() {
FilterRegistrationBean<ResourceUrlEncodingFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new ResourceUrlEncodingFilter());
registration.addUrlPatterns("/*");
return registration;
}

Related

The origin server did not find a current representation for the target resource or is not willing to disclose that one exists error

Web.xml
Books Management
<servlet>
<servlet-name>BooksManagement</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>BooksManagement</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/student.jsp</welcome-file>
</welcome-file-list>
My controller is AddStudentController
#Controller
public class AddStudentController {
#RequestMapping(value = "/student", method = RequestMethod.GET)
public ModelAndView student() {
return new ModelAndView("student", "command", new Students());
}
#RequestMapping(value = "/addStudent", method = RequestMethod.POST)
public String addStudent(#ModelAttribute("SpringWeb") Students student,ModelMap model) {
model.addAttribute("firstName", student.getFirstName());
model.addAttribute("lastName", student.getLastName());
model.addAttribute("id", student.getId());
return "result";
}
}
Folder Structure
The origin server did not find a current representation for the target resource or is not willing to disclose that one exists error
At first, I was trying to hit student.jsp without hitting in index.jsp. After I give Click here... in index.jsp.
Also, added
<welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list>
in web.xml
Now it's solved
As Controller was searching /student it was nowhere mentioned
#Controller
public class AddStudentController {
#RequestMapping(value = "/student", method = RequestMethod.GET)
public ModelAndView student() {
return new ModelAndView("student", "command", new Students());
}

Not able to get rid of user credential request pop up using Spring Security?

I am integrating Spring Security into my Spring MVC and Angular App.
Versions:
Spring Security: 4.1.5.RELEASE
Spring MVC: 4.2.0.RELEASE
Angular: 4
After integration, I see that browser is showing pop up for user name and password. Even after following changes, I am not able to get rid of the pop up and proceed further to my custom login form in angular.
To start with I am using http basic authentication mechanism.
For this created following SecurityConfig.java.
[Updated]
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// #formatter:on
auth.inMemoryAuthentication().withUser("user1").password("user1").roles("USER").and().withUser("user2")
.password("user2").roles("USER").and().withUser("admin").password("admin").roles("ADMIN");
// #formatter:off
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:on
http
.authorizeRequests().antMatchers("/index.html", "/", "/login", "*.*", "/*.bundle.*", "/*.ico")
.permitAll().anyRequest().authenticated().and().csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
// #formatter:off
}
}
For resource and path resolution, created following ServletContextConfiguration.java .
#Configuration
#EnableWebMvc
public class ServletContextConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(true).ignoreAcceptHeader(true).useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON).mediaType("html",
MediaType.TEXT_HTML)
.mediaType("xml", MediaType.APPLICATION_XML).mediaType("json",
MediaType.APPLICATION_JSON);
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean(name = "contentNegotiatingViewResolver")
public ViewResolver getContentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("/dist/").resourceChain(true)
.addResolver(new PathResourceResolver());
}
}
Following is my web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Application</display-name>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
<url-pattern>*.html</url-pattern>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
I am using weblogic server to deploy war file.
weblogic.xml
<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app
xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
<wls:context-root>/</wls:context-root>
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>org.slf4j.*</wls:package-name>
<wls:package-name>org.springframework.*</wls:package-name>
<wls:package-name>org.springframework.web.servlet.view.*</wls:package-name>
<wls:package-name>oracle.core.*</wls:package-name>
<wls:package-name>oracle.jdbc.*</wls:package-name>
<wls:package-name>oracle.net.*</wls:package-name>
<wls:package-name>oracle.sql.*</wls:package-name>
<wls:package-name>oracle.security.*</wls:package-name>
<wls:package-name>org.hibernate.*</wls:package-name>
<wls:package-name>com.fasterxml.*</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
</wls:weblogic-web-app>
Angular Changes:
In app.module.ts introduced http interceptor to inject http header X-Requested-With as suggested here.
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { RouterModule, Routes } from '#angular/router';
import { NgModule } from '#angular/core';
import { Injectable } from '#angular/core';
import {
HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTERCEPTORS
} from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { AppComponent } from './app.component';
import { StoreComponent } from './components/store/store.component';
import { StoreService } from './services/store.service';
import { LoginComponent } from './components/login/login.component';
import { LogoutComponent } from './components/logout/logout.component';
#Injectable()
export class XhrInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
const xhr = req.clone({
headers: req.headers.set('X-Requested-With', 'XMLHttpRequest')
});
console.log(">>>>>>>>>>HttpRequest intercepted...");
return next.handle(xhr);
}
}
const appRoutes: Routes = [
{ path:'', pathMatch: 'full', redirectTo: 'login' },
{ path: 'login', component: LoginComponent},
{ path: 'logout', component: LogoutComponent },
{ path: 'store', component: StoreComponent }
]
#NgModule({
declarations: [
AppComponent,
StoreComponent,
LoginComponent,
LogoutComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
RouterModule.forRoot(appRoutes)
],
providers: [ StoreService, { provide: HTTP_INTERCEPTORS, useClass: XhrInterceptor, multi: true } ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
By some reason, still I am able to see the default user name and password pop up from browser.
In web console, I don't see the X-Requested-With header. Also, I don't see my console log which should have been printed while http request is intercepted.
I think, request might not be reaching angular client and something wrong happened in server side.
What could be missing here?
Update:
As suggested, I have replaced http.basic() request with http.authorizeRequests(). Now, pop up is not displayed for /login request. But after once I try to submit user credentials in my custom login page by calling /authenticate, again I see the pop up :(
What could be missing here.
Please clarify.
Thanks.
this is due to http.httpBasic() in your config, it should be http.authorizeRequests()
You are still using spring security's http basic authentication, that is why is it showing basic authentication pop up, dont use it , use http.autherizeRequest() and using machers permit your login url.
And in routemodule define same path for login component. It will work.

How to properly use multiple controllers in Spring MVC

I am trying to use 2 controllers with one dispatcher servlet in Spring MVC. But I am running into 404 errors when trying to render the views. The dispatcher is pretty straightforward, from web.xml:
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
and with the following configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
...
<context:component-scan base-package="com.mycompany.azalea" />
<mvc:annotation-driven />
</beans>
The controllers are:
package com.mycompany.azalea;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping(value = "/home")
public class homeController {
#RequestMapping(value = "/")
public String home() {
return "index";
}
}
and
package com.mycompany.azalea;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping(value = "/data")
public class dataController {
#RequestMapping(value = "/")
public String home() {
return "index";
}
}
and I am using a pretty standard resolver:
#Configuration
public class AppConfig {
// Resolve logical view names to .jsp resources in the /WEB-INF/views directory
#Bean
ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
Views are set up under WEB-INF/views/home/ and WEB-INF/views/data/
However if I try to request a URL like http://localhost:8080/Azalea/home/
I get an entry in the GlassFish log:
SEVERE: PWC6117: File ".../build/web/home/WEB-INF/views/index.jsp" not found
instead of the expected request for
".../build/web/WEB-INF/views/home/index.jsp"
Same pattern for "/data". It essentially looks like the request mapping is inserted into the wrong position in the request.
My current work around is to modify the resolver to
resolver.setPrefix("../WEB-INF/views/");
and return the following from the controller:
public class homeController {
#RequestMapping(value = "/")
public String home() {
return "home/index";
}
}
But this seems to be a suboptimal solution. Please let me know if you have any suggestions.
You almost got it right. The prefix has to be absolute here to make it work the way you want it to. That is: The prefix for the view-resolver has to be set as an absolute:
resolver.setPrefix("WEB-INF/views/");
And, when you return the view names from the #RequestMapping methods, they have to be the paths relative to your view-resolver's prefix path. So, in the homeController, you should return home/index, and in your dataController, you should return data/index.

How do I map Spring MVC controller to a uri with and without trailing slash?

I have a Spring Controller with several RequestMappings for different URIs. My servlet is "ui". The servlet's base URI only works with a trailing slash. I would like my users to not have to enter the trailing slash.
This URI works:
http://localhost/myapp/ui/
This one does not:
http://localhost/myapp/ui
It gives me a HTTP Status 404 message.
The servlet and mapping from my web.xml are:
<servlet>
<servlet-name>ui</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ui</servlet-name>
<url-pattern>/ui/*</url-pattern>
</servlet-mapping>
My Controller:
#Controller
public class UiRootController {
#RequestMapping(value={"","/"})
public ModelAndView mainPage() {
DataModel model = initModel();
model.setView("intro");
return new ModelAndView("main", "model", model);
}
#RequestMapping(value={"/other"})
public ModelAndView otherPage() {
DataModel model = initModel();
model.setView("otherPage");
return new ModelAndView("other", "model", model);
}
}
Using Springboot, my app could reply both with and without trailing slash by setting #RequestMapping's "value" option to the empty string:
#RestController
#RequestMapping("/some")
public class SomeController {
// value = "/" (default) ,
// would limit valid url to that with trailing slash.
#RequestMapping(value = "", method = RequestMethod.GET)
public Collection<Student> getAllStudents() {
String msg = "getting all Students";
out.println(msg);
return StudentService.getAllStudents();
}
}
If your web application exists in the web server's webapps directory, for example webapps/myapp/ then the root of this application context can be accessed at http://localhost:8080/myapp/ assuming the default Tomcat port. This should work with or without the trailing slash, I think by default - certainly that is the case in Jetty v8.1.5
Once you hit /myapp the Spring DispatcherServlet takes over, routing requests to the <servlet-name> as configured in your web.xml, which in your case is /ui/*.
The DispatcherServlet then routes all requests from http://localhost/myapp/ui/ to the #Controllers.
In the Controller itself you can use #RequestMapping(value = "/*") for the mainPage() method, which will result in both http://localhost/myapp/ui/ and http://localhost/myapp/ui being routed to mainPage().
Note: you should also be using Spring >= v3.0.3 due to SPR-7064
For completeness, here are the files I tested this with:
src/main/java/controllers/UIRootController.java
package controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class UiRootController {
#RequestMapping(value = "/*")
public ModelAndView mainPage() {
return new ModelAndView("index");
}
#RequestMapping(value={"/other"})
public ModelAndView otherPage() {
return new ModelAndView("other");
}
}
WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="false">
<servlet>
<servlet-name>ui</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<!-- spring automatically discovers /WEB-INF/<servlet-name>-servlet.xml -->
</servlet>
<servlet-mapping>
<servlet-name>ui</servlet-name>
<url-pattern>/ui/*</url-pattern>
</servlet-mapping>
</web-app>
WEB-INF/ui-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="controllers" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:order="2"
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/views/"
p:suffix=".jsp"/>
</beans>
And also 2 JSP files at WEB-INF/views/index.jsp and WEB-INF/views/other.jsp.
Result:
http://localhost/myapp/ -> directory listing
http://localhost/myapp/ui and http://localhost/myapp/ui/ -> index.jsp
http://localhost/myapp/ui/other and http://localhost/myapp/ui/other/ -> other.jsp
Hope this helps!
PathMatchConfigurer api allows you to configure various settings
related to URL mapping and path matching. As per the latest version of spring, trail path matching is enabled by default. For customization, check the below example.
For Java-based configuration
#Configuration
#EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseTrailingSlashMatch(true);
}
}
For XML-based configuration
<mvc:annotation-driven>
<mvc:path-matching trailing-slash="true"/>
</mvc:annotation-driven>
For #RequestMapping("/foo"), if trailing slash match set to false, example.com/foo/ != example.com/foo and if it's set to true (default), example.com/foo/ == example.com/foo
Cheers!
I eventually added a new RequestMapping to redirect the /ui requests to /ui/.
Also removed the empty string mapping from the mainPage's RequestMapping.
No edit required to web.xml.
Ended up with something like this in my controller:
#RequestMapping(value="/ui")
public ModelAndView redirectToMainPage() {
return new ModelAndView("redirect:/ui/");
}
#RequestMapping(value="/")
public ModelAndView mainPage() {
DataModel model = initModel();
model.setView("intro");
return new ModelAndView("main", "model", model);
}
#RequestMapping(value={"/other"})
public ModelAndView otherPage() {
DataModel model = initModel();
model.setView("otherPage");
return new ModelAndView("other", "model", model);
}
Now the URL http://myhost/myapp/ui redirects to http://myhost/myapp/ui/ and then my controller displays the introductory page.
Another solution I found is to not give the request mapping for mainPage() a value:
#RequestMapping
public ModelAndView mainPage() {
DataModel model = initModel();
model.setView("intro");
return new ModelAndView("main", "model", model);
}
try adding
#RequestMapping(method = RequestMethod.GET)
public String list() {
return "redirect:/strategy/list";
}
the result:
#RequestMapping(value = "/strategy")
public class StrategyController {
static Logger logger = LoggerFactory.getLogger(StrategyController.class);
#Autowired
private StrategyService strategyService;
#Autowired
private MessageSource messageSource;
#RequestMapping(method = RequestMethod.GET)
public String list() {
return "redirect:/strategy/list";
}
#RequestMapping(value = {"/", "/list"}, method = RequestMethod.GET)
public String listOfStrategies(Model model) {
logger.info("IN: Strategy/list-GET");
List<Strategy> strategies = strategyService.getStrategies();
model.addAttribute("strategies", strategies);
// if there was an error in /add, we do not want to overwrite
// the existing strategy object containing the errors.
if (!model.containsAttribute("strategy")) {
logger.info("Adding Strategy object to model");
Strategy strategy = new Strategy();
model.addAttribute("strategy", strategy);
}
return "strategy-list";
}
** credits:
Advanced #RequestMapping tricks – Controller root and URI Template
Not sure if this is the ideal approach, but what worked for me was to treat them as if they were two different paths and make them both accepted by each of my endpoints, such as.
#RestController
#RequestMapping("/api/mb/actor")
public class ActorController {
#GetMapping({"", "/"})
public ResponseEntity<Object> getAllActors() {
...
}
#GetMapping({"/{actorId}", "/{actorId}/"})
public ResponseEntity<Object> getActor(#PathVariable UUID actorId) {
...
}
There may be best ways to do this and to avoid this duplication, and I'd love to know that. However, what I found when I tried using configurer.setUseTrailingSlashMatch(true); is that broken paths also start becoming accepted, such as /api/mb////actor (with many slashs), and that's why I ended up going the multiple paths instead.

Servlet NOT_FOUND (GWT+AppEngine)

I want to develop my first AppEngine application, that will also use GWT. Since I don't have any experience with GWT and AppEngine, I started with tutorials on GWT site, and after succefully completing Getting Started, I started working on http://code.google.com/webtoolkit/doc/latest/tutorial/appengine.html
But I ran into a problem, and I don't have a clue why :)
I am trying to check if user is logged in, like in "Personalize the application with the User Service" section of tutorial.
But when I run the code itself, I get an error:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 404 NOT_FOUND</title>
</head>
<body><h2>HTTP ERROR 404</h2>
<p>Problem accessing /parkmeweb/login. Reason:
<pre> NOT_FOUND</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/>
</body>
</html>
And here are my files:
LoginService
#RemoteServiceRelativePath("login")
public interface LoginService extends RemoteService {
public LoginInfo login(String requestUri);
}
LoginServiceAsync
public interface LoginServiceAsync {
public void login(String requestUri, AsyncCallback<LoginInfo> async);
}
LoginServiceImpl
public class LoginServiceImpl extends RemoteServiceServlet implements
LoginService {
public LoginInfo login(String requestUri) {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
LoginInfo loginInfo = new LoginInfo();
if (user != null) {
loginInfo.setLoggedIn(true);
loginInfo.setEmailAddress(user.getEmail());
loginInfo.setNickname(user.getNickname());
loginInfo.setLogoutUrl(userService.createLogoutURL(requestUri));
} else {
loginInfo.setLoggedIn(false);
loginInfo.setLoginUrl(userService.createLoginURL(requestUri));
}
return loginInfo;
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Servlets -->
<servlet>
<servlet-name>loginService</servlet-name>
<servlet-class>com.parkme.parkmeweb.server.LoginServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginService</servlet-name>
<url-pattern>/parkmeweb/login/</url-pattern>
</servlet-mapping>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>ParkmeWeb.html</welcome-file>
</welcome-file-list>
</web-app>
All this I getting called from onModuleLoad:
public void onModuleLoad() {
LoginServiceAsync loginService = GWT.create(LoginService.class);
loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() {
public void onFailure(Throwable error) {
//this is where error is thrown
Window.alert(error.getMessage());
}
public void onSuccess(LoginInfo result) {
loginInfo = result;
if(loginInfo.isLoggedIn()) {
return;
} else {
loadLogin();
}
}
});
}
Just by looking at this, I can't see any problems, and I should probably looking for problems elsewhere, but I would like to hear some ideas what went wrong.
The handler is for /parkmweweb/login/, but you're visiting /parkmeweb/login - without the trailing slash.
Facing the same problem. But I tried to deploy it to google. The servlet is accessible and no problem. It looks like being a problem with GWT + Eclipse, not sure exactly where. Hope they can fix it, other wise testing is difficult.
I just restarted Eclipse and that fixed the problem.
Problem started when I switched from jre1.7 to jre1.6 both x64.

Categories