I'm using Spring Boot with embeded Tomcat.
When it starts it logs into console:
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/home]}" onto public java.lang.String com.vlad.pet.contactlist.webapp.controller.SampleController.helloWorld(org.springframework.ui.Model)
So I guess the URL is mapped to the controller.
But http://localhost:8090/home gives me an error 404.
There was an unexpected error (type=Not Found, status=404).
No message available
Application.java
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
//overrides the configure() method to point to itself, so Spring can find the main configuration.
#Override
protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Bean
public ViewResolver getViewResolver() {
final TilesViewResolver resolver = new TilesViewResolver();
resolver.setViewClass(TilesView.class);
return resolver;
}
#Bean
public TilesConfigurer getTilesConfigurer() {
final TilesConfigurer configurer = new TilesConfigurer();
configurer.setDefinitions("WEB-INF/tiles/tiles.xml");
configurer.setCheckRefresh(true);
return configurer;
}
}
SampleController.java
#Controller
public class SampleController {
#RequestMapping (value = "/home")
public String helloWorld(Model model) {
model.addAttribute("pageTitle", "home");
return "base";
}
}
tiles.xml
<tiles-definitions>
<definition name="base" template="/WEB-INF/tiles/basic/basic-template.jsp">
<put-attribute name="head" value="/WEB-INF/tiles/basic/head.jsp" />
</definition>
</tiles-definitions>
My project structure
You can use #RestController instead of #Controller.
#RestController
public class SampleController {
...
You're returning 'home' from your controller method, but I don't see a home.jsp on your project structure.
I solved this problem by enabling default servlet:
#Configuration
#EnableWebMvc
public class Config extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
Source: Configure ViewResolver with Spring Boot and annotations gives No mapping found for HTTP request with URI error
In my case, my eclipse project was showing an error. i had to do mvn install from eclipse, update maven dependencies and then start the server from eclipse.
Related
We are getting the unable to infer base url when we tried to access the swagger url
We use Spring 5.3.18 and we don't use spring security.
We are using the Spring fox 3.0.0 version, and below is the Swagger Config and Web Config code.
#Profile("swagger")
#Configuration
#EnableSwagger2
#Import(SpringDataRestConfiguration.class)
public class SwaggerConfig {
private static final String DEFAULT = "1. Default";
#Bean
public Docket apiDocket() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("basepackage.rest.controller"))
.paths(PathSelectors.any()).build();
}
}
#EnableWebMvc
#Configuration
#Profile("swagger")
public class WebConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
I just start learning SpringBoot.
I use spring boot build-in tomcat get my spring boot program run. But when I try to visit the page, it gives me a Whitelabel Error Page.
When I start this program, it shows as follow:
I think my program and tomcat start successfully.
This is my start code:
DemoApplication.java
#SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(DemoApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
This is my Controller code:
BookController.java
#Controller
public class BookController {
private IBookService bookService;
public BookController(IBookService bookService) {
this.bookService = bookService;
}
#RequestMapping(value = "/book_list", method = RequestMethod.GET)
public String getAllBook(Model model, HttpSession httpSession, HttpRequest httpRequest) throws Exception {
List<Book> list = bookService.getAllBook();
model.addAttribute("bookList", list);
return "book";
}
}
So if I visit 'localhost:8080/bookstore/book_list', it will find the controller and this controller should help me go to the /WEB-INF/jsp/book.jsp because my WebMvcConfig like following:
WebMvcConfig.java
#Configuration
public class WebMvcConfig {
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
}
But why this is a white page?
This is my program structure:
DemoApplication is in a demo subpackage. The default is that it only scans subpackages of the class annotated with #SpringBootApplication, so it doesn't find any of your components.
Two ways to fix:
Move the class out of the demo package.
This is what Spring Boot demo applications usually do.
Specify the packages to scan:
#SpringBootApplication(scanBasePackages = "com.zx")
Alternatively, use #ComponentScan, same thing:
#SpringBootApplication
#ComponentScan("com.zx")
I'm currently working on a Web-App using Spring boot (including spring security) and thymeleaf. At the moment i'm trying to integrate internationalization support for the languages english and german as a start.
For the basics I've followed this Tutorial and tried to get their example to work.
Now if I go to Localhost:8443/international and choose one of the languages the URL gets built correctly to .../international?lang=en. Thymeleaf even reads the fields in the .propperties file marked as default. But I can't get it to actually switch the language no matter what I do.
Code:
#Configuration
#EnableWebMvc
#EnableAutoConfiguration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US);
return slr;
}
}
Like this I assume it's taking the default messages.propperties. However if I put the LocaleResolver Bean into my
public class Application extends SpringBootServletInitializer
class where the main method is, it takes whatever language is set as default Locale there.
From where I am at right now I conclude that my .propperties files are fine and can be read but something with the LocaleChangeInterceptor does not work propperly. I went into debug mode but any breakpoints in the WebConfig class did not trigger at all.
One assumption of mine would be Spring security messing something up, such that the ?lang request can't be resolved. (Tried both logged-in and logged-out).
Would be really glad if anyone has some idea on how to resolve the issue, thanks for every reply in advance!
My Application class:
#SpringBootApplication
#EnableMongoRepositories(basePackageClasses = UserRepository.class)
#ComponentScan(basePackages = { "my.company.controller", "my.company.Services", "java.lang.String","my.company.Services.Security" })
#EnableConfigurationProperties(my.company.Services.Storage.StorageProperties.class)
public class Application extends SpringBootServletInitializer {
#Autowired
private UserRepository repository;
#Autowired
private SecUserDetailsService userDetailService;
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Bean
CommandLineRunner init(StorageService storageService) {
return (args) -> {
repository.deleteAll();
userDetailService.addUser("bob", "ross", "admin");
userDetailService.addUser("1", "1", "superuser");
userDetailService.addUser("2", "2", "admin");
System.out.println("All users currently in DB:");
System.out.println("-------------------------------");
for (User user1 : repository.findAll()) {
System.out.println(user1);
}
System.out.println();
// storageService.deleteAll();
try {
storageService.init();
} catch (StorageException e) {
System.out.println("Ordner schon vorhanden");
}
};
//If i add this here french gets picked as default language, changing does still not work
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.FRENCH);
return slr;
}
}
Try removing the #ComponentScan annotation. The #SpringBootApplication does the component scanning automatically. I guess your WebConfig class is not loaded.
I passed one day and a half looking for answer, but this thing is going to put me crazy!
My teammates and I are working on an project, based on springboot. I work specificaly on the administration part, which is a web administration.
There are mainly three layers on my project: Controllers which use Services which use Repositories.
I want my project work with #Transactional for the Service layer (we made some successful efforts until now to use only annotations for configuration).
But, it seems that it doesn't work: One of my service throws a RuntimeException and no rollback is done. I allready read all the proposition in the others sibling subjects. The only thing, related to my problem, that i'm not sure to do neatly is the contexts configuration. Eventhow, i'm not sure that it's really my problem.
I show you the actual configuration:
#SpringBootApplication
#EnableScheduling
#EnableTransactionManagement
public class Application extends SpringBootServletInitializer {
#Value("${ajp.port}")
private int ajpPort;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {};
tomcat.addAdditionalTomcatConnectors(createConnector(ajpPort));
return tomcat;
}
#Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return container -> {
ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/static/401.html");
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/static/404.html");
container.addErrorPages(error401Page, error404Page);
};
}
#Bean
public EmailValidator emailValidator() {
return EmailValidator.getInstance();
}
private static Connector createConnector(int ajpPort) {
Connector connector = new Connector("AJP/1.3");
connector.setPort(ajpPort);
return connector;
}
}
The web config:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Autowired
private RequestProcessingTimeInterceptor requestProcessingTimeInterceptor;
#Autowired
private CertificateInterceptor certificateInterceptor;
#Autowired
private ProfilesAuthorizationInterceptor profilesAuthorizationInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestProcessingTimeInterceptor);
registry.addInterceptor(certificateInterceptor);
registry.addInterceptor(profilesAuthorizationInterceptor);
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setExposeContextBeansAsAttributes(true);
resolver.setPrefix("/WEB-INF/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/admin/css/**").addResourceLocations("/WEB-INF/admin/css/").setCachePeriod(CACHE_PERIOD);
registry.addResourceHandler("/admin/img/**").addResourceLocations("/WEB-INF/admin/img/").setCachePeriod(CACHE_PERIOD);
registry.addResourceHandler("/admin/js/**").addResourceLocations("/WEB-INF/admin/js/").setCachePeriod(CACHE_PERIOD);
registry.addResourceHandler("/admin/plugins/**").addResourceLocations("/WEB-INF/admin/plugins/").setCachePeriod(CACHE_PERIOD);
}
}
A Controler-like:
#RestController
#RequestMapping("/pathA")
public class ControlerA {
#Autowired
public ServiceA serviceA;
#RequestMapping(value = "{id}", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public A getA(#PathVariable long id) {
return serviceA.getA(id);
}
}
A Service-like (interface + implémentation):
public interface ServiceA {
A getA(long id);
}
#Service
#Transactional
public class ServiceAImpl implements ServiceA {
#Autowired
public RepositoryA repositoryA;
public A getA(long id) {
(...)
A a = repositoryA.findOne(id);
a.updatesomething(something);
repositoryA.update(a);
doOtherThing(a); //throw RuntimeException
(...)
return a;
}
}
And the Repository:
#Repository
public interface RepositoryA extends JpaRepository<A, Long> {
(...)
}
Here is the configuration of the MySQL database:
# Configuration de la base de donnée
spring.datasource.url=jdbc:mysql://localhost/name_innodb
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.testOnBorrow=true
spring.datasource.validationQuery=SELECT 1
I know that repository transaction works by default (I saw it, when a SQLException happen). But in the service layer, nothing happen (cf. the throwing exception line) ; when the exception is thrown, the update is done and not rollback. Then it mean that my #Transactional is ignored.
Edit :
I manage to get a transaction like I want, adding #Transactional on the method getA(...) of the Controller. It works, but it's not the place to manage Transaction.
Then my question is: How can I make it work?
Ok, after some days of brainstorming, I found!
The only reasonnable answer is to take care about your Configuration class. My problem was only a crossover configuration problem which leaded to a DispatcherServlet configuration who caused the mess.
Related Subject: For web MVC Spring app should #Transactional go on controller or service?
Edit:
I add some details because it'll be hard to find some information in order to separate context. And I'm still calibrating the configuration because there's no complete and exhaustive information about all the spring's annotations.
You could create parent and child context like this:
#SpringBootApplication
#ComponentScan({"com.mycompany.service", "com.mycompany.interceptors","com.mycompany.manager"})
#PropertySource("file:config/application.properties")
public class ParentConfig{
public static void main(String[] args) {
new SpringApplicationBuilder()
.parent(ParentConfig.class)
.child(ChildConfig1.class, ChildConfig2.class, ChildConfig3.class, ..., ChildConfigN.class)
.run(args);
}
(...)
}
I'm still wondering why I must add the #PropertySource in order children are aware of property values, why "classpath:path" have not work in #PropertySource, why I have to add a static PropertySourcesPlaceholderConfigurer for using #Value in my children (before I do that, i.e without this hierarchical contexts, every context was aware of the properties)
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
and I'm still playing with annotations in order every configuration work.
Edit:
I finally have found something in order to work correctly with spring configuration: Different configurations must respect packaging hierarchy.
I stop working with parent and child configuration and let spring work. I ordonate my different config class like this:
MainConfig
|
|__________my.package.mvc.MVCConfig
|
|__________my.package.schedulers.SchedulerConfig
|
|
and so on..
And in my MainConfig I add:
#ComponentScan({"my.package.mvc", "my.package.services", "my.package.interceptors","my.package.managers", "my.package.schedulers"})
And everything is good now! Mostly, MVCConfig can not create conflict with services, because of the different hierarchy.
I got a working spring boot rest service. When the path is wrong it doesn't return anything. No response At all. At the same time it doesn't throw error either. Ideally I expected a 404 not found error.
I got a GlobalErrorHandler
#ControllerAdvice
public class GlobalErrorHandler extends ResponseEntityExceptionHandler {
}
There is this method in ResponseEntityExceptionHandler
protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
return handleExceptionInternal(ex, null, headers, status, request);
}
I have marked error.whitelabel.enabled=false in my properties
What else must I do for this service to throw a 404 not found response back to clients
I referred a lot of threads and don't see this trouble faced by anybody.
This is my main application class
#EnableAutoConfiguration // Sprint Boot Auto Configuration
#ComponentScan(basePackages = "com.xxxx")
#EnableJpaRepositories("com.xxxxxxxx") // To segregate MongoDB
// and JPA repositories.
// Otherwise not needed.
#EnableSwagger // auto generation of API docs
#SpringBootApplication
#EnableAspectJAutoProxy
#EnableConfigurationProperties
public class Application extends SpringBootServletInitializer {
private static Class<Application> appClass = Application.class;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(appClass).properties(getProperties());
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public FilterRegistrationBean correlationHeaderFilter() {
FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean.setFilter(new CorrelationHeaderFilter());
filterRegBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegBean;
}
#ConfigurationProperties(prefix = "spring.datasource")
#Bean
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
static Properties getProperties() {
Properties props = new Properties();
props.put("spring.config.location", "classpath:/");
return props;
}
#Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
WebMvcConfigurerAdapter webMvcConfigurerAdapter = new WebMvcConfigurerAdapter() {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).favorParameter(true).parameterName("media-type")
.ignoreAcceptHeader(false).useJaf(false).defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML).mediaType("json", MediaType.APPLICATION_JSON);
}
};
return webMvcConfigurerAdapter;
}
#Bean
public RequestMappingHandlerMapping defaultAnnotationHandlerMapping() {
RequestMappingHandlerMapping bean = new RequestMappingHandlerMapping();
bean.setUseSuffixPatternMatch(false);
return bean;
}
}
The solution is pretty easy:
First you need to implement the controller that will handle all error cases. This controller must have #ControllerAdvice -- required to define #ExceptionHandler that apply to all #RequestMappings.
#ControllerAdvice
public class ExceptionHandlerController {
#ExceptionHandler(NoHandlerFoundException.class)
#ResponseStatus(value= HttpStatus.NOT_FOUND)
#ResponseBody
public ErrorResponse requestHandlingNoHandlerFound() {
return new ErrorResponse("custom_404", "message for 404 error code");
}
}
Provide exception you want to override response in #ExceptionHandler. NoHandlerFoundException is an exception that will be generated when Spring will not be able to delegate request (404 case). You also can specify Throwable to override any exceptions.
Second you need to tell Spring to throw exception in case of 404 (could not resolve handler):
#SpringBootApplication
#EnableWebMvc
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
}
}
Result when I use non defined URL
{
"errorCode": "custom_404",
"errorMessage": "message for 404 error code"
}
UPDATE: In case you configure your SpringBoot application using application.properties then you need to add the following properties instead of configuring DispatcherServlet in main method (thanks to #mengchengfeng):
spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false
I know this is an old question but here is another way to configure the DispatcherServlet in code but not in the main class. You can use a separate #Configuration class:
#EnableWebMvc
#Configuration
public class ExceptionHandlingConfig {
#Autowired
private DispatcherServlet dispatcherServlet;
#PostConstruct
private void configureDispatcherServlet() {
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
}
}
Please not that this does not work without the #EnableWebMvc annotation.
Add this to your Properties file.
spring:
mvc:
throw-exception-if-no-handler-found: true
web:
resources:
add-mappings: false
In your #ControllerAdvice class add this:
#ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<Object> handleNoHandlerFound404() {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);;
}