I am trying to implement a web application using Springboot. but when I request methods I get 404 Error. Springboot cannot find Jsp files.
this is my Controller Code:
#PostMapping(value = "/loginSuccess")
public ModelAndView loginSuccess() {
System.out.println("in login success");
return new ModelAndView("index");
}
#GetMapping(value = "/loginError")
public ModelAndView showLoginError() {
System.out.println("in login error");
return new ModelAndView("error");
}
and this is my SecurityConfig:
#ComponentScan
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private EmployeeRepository employeeRepository;
#Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Bean
public UserDetailsService userDetailsService(){
return new EmployeeDetailService(employeeRepository, passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.formLogin()
.successForwardUrl("/loginSuccess")
.failureUrl("/loginError")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/").permitAll()
.and()
.httpBasic();
}
}
I also specified prefix and suffix in application.properties:
spring.mvc.view.prefix=/static/
spring.mvc.view.suffix=.jsp
I also have these dependencies in my pom file:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
and this is my Project Structure:
can anyone tell me what is the problem?
The main template engines for SpringBoot are Thymeleaf, Groovy, FreeMarker, Jade. In the reference guide:
JSP should be avoided if possible, there are several known limitations
when using them with embedded servlet containers.
An executable jar will not work because of a hard coded file pattern
in Tomcat.
If the JSPs are legacy or proprietary codes that you can't convert, you have to do a few things in order to develop/maintain, compile and kinda run a SpringBootApplication running them in Intellij:
maven: your pom must be a 'war' package.
That will makes intellij look for and compile the JSPs right.
web facet: put your .jsp files in a folder where they are expected to be in a webapp: src/main/webapp/WEB-INF/jsp/
The jsp will never be 'compiled'/'interpretable' in static.
spring facet: set the prefix to /WEB-INF/jsp/ in your application.properties
tomcat: have those dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
build runnable war: make an Intellij "maven configuration" that run :
clean install -f pom.xml
run that war: make an Intellij "jar configuration" with those settings:
path to jar : <the path to the war file in the target folder>
before launch : run the "maven configuration" you created
i had a similar problem and for me specifying the web resource directory containing the JSP files resolved the issue.
open project structure and under modules -> web -> web resource directory specify the directory in which your view are contained (in this case webapp)
open application.properties
specify the folder within your webresource directory which contains your views as prefix (in this case /views/)
specify your view suffix .jsp
this should enable intelij to resolve the views returned by the controller.
Related
I use an embedded Jetty (11.0.13) server with Jersey (3.1.0) that provides a simple REST interface which returns JSON objects. The JSON objects are serialized using Jackson.
The setup works fine as long as I don´t use Java´s module system.
But when I add the module-info.java file (see below), I get the following error as soon as I call the service.
WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 2
java.lang.NoClassDefFoundError: jakarta/xml/bind/annotation/XmlElement
at com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector.<init>(JakartaXmlBindAnnotationIntrospector.java:137)
...
Caused by: java.lang.ClassNotFoundException: jakarta.xml.bind.annotation.XmlElement
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 83 more
MultiException stack 2 of 2
java.lang.IllegalStateException: Unable to perform operation: post construct on org.glassfish.jersey.jackson.internal.DefaultJacksonJaxbJsonProvider
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:429)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:466)
...
To make it work, I have to add the JAX-B-API to the pom.xml and to the module-info.java.
The error only occurs when using Java modules. When I simply delete the module-info.java file, everythink works fine even without the JAX-B dependency.
This is the point where I am really confused. Why do I need the JAX-B dependency when I use the module system, but not when I don´t use it? And why does the ClassNotFoundException even occur? Shouldn´t warn the module system about missing dependencies on startup?
I hope someone can explain that. It took me days to make it work.
This is the setup that produces the issue:
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>11.0.13</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>11.0.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
</project>
Main.java
public class Main {
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
server.setStopAtShutdown(true);
ServletContextHandler context = new ServletContextHandler(server, "/");
ServletHolder servletHolder = context.addServlet(ServletContainer.class, "/*");
servletHolder.setInitParameter("jersey.config.server.provider.packages", "com.example.demo");
servletHolder.setInitParameter("jersey.config.server.wadl.disableWadl", "true");
server.start();
}
}
DemoResource.java
#Path("/hello")
public class DemoResource {
#GET
#Produces("application/json")
public HelloDto hello() {
return new HelloDto("Hello, World!");
}
public record HelloDto(String value) {
#JsonGetter("value")
public String value() {
return this.value;
}
}
}
module-info.java
module demo {
requires org.eclipse.jetty.server;
requires org.eclipse.jetty.servlet;
requires jersey.container.servlet.core;
requires jakarta.ws.rs;
requires com.fasterxml.jackson.annotation;
}
This is the standard JVM behavior of classpath (old school Java) and modulepath (new school Java Platform Module System, aka JPMS).
Once you have a module-info.class you have a modulepath active, and all of the access rules it has.
Your runtime can have both at the same time, and this is quite normal.
Don't rely on old school classpath to get around bad code and bad behavior, use JPMS and module-info.class and you'll know what the developers of those projects jars intend for you to use (you won't be allowed to use internal classes for example, as those are highly volatile and can change at a moments notice).
jakarta.xml.bind is required by HK2 to operate, so you have to declare it in your build dependencies to just compile, and then your module-info.java to be able to access it.
Check the other answers here on Stackoverflow for advice on how to use module-info.java properly (there's far more to it than just requires <module>).
I am new to Spring Framework. Trying to make a Java based Spring MVC project. Here is my main application class
#SpringBootApplication
#ComponentScan
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
#Controller
public class HelloController {
#RequestMapping("/")
public String hello(){
return "hello";
}
}
When I run the project I get the error
There was an unexpected error (type=Not Found, status=404).
No message available
Why Spring can not display JSP files?
Add following to application.properties
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
Edit :You can refer sample project here
Below step is not required, but worth a try.
As per another post, you need following dependencies
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
I am trying to change spring xml settings to pure code based setting.
So I read official documents and some posts from blogs.
e.g. http://docs.spring.io/spring-framework/docs/4.1.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html
An I made a code like ...
public class TestInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container)
throws ServletException {
// TODO Auto-generated method stub
System.out.println("on Startup method has called.");
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(RootConfig.class);
container.
//container.addListener(new ContextLoaderListener(ctx));
}
};
A problem here. In those pages, they use addListener(new ContextLoaderListener(ctx)) method to set context. However my eclipse can not find that method from container variable.
I do not know any clue why my container variable(javax.servlet.ServletContext instance) can not read this method.
Thanks for your answer:D
P.S.
My spring version is 4.1.6.RELEASE and I include servlet3.0, spring-context, spring-webmvc on pom.xml.
========================
Maybe I got some communication problem, So I summarize this :D
javax.servlet.ServletContext doc clearly state that it has method
addListener >>
http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html
have to use Spring WebApplicationInitializer.onStartup(ServletContext) to set basic setting via Java source code, not XML
Can not load addListener from ServletContext class.
=================================
Edit. This is not error on console. However it is the only message I got.
It is from eclipse toolkit.
The method addListener(ContextLoaderListener) is undefined for the type ServletContext
than recommendation is Add cast to 'container'
To follow up on what #JuneyoungOh has commented, turns out that the problem is because of conflicting dependency. And these are the ways to solve this problem :
* make version 3.0.1 and artifactId 'javax.servlet-api' or
* add tomcat(in my case 7.0) to project build path and remove servlet dependency.
In my case the problem was because of Spring-Support which is depended on "javax.servlet" and I just excluded it:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-support</artifactId>
<version>${spring-support.version}</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
In my case there was:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
notice, that artifactId is servlet-api, not javax.servlet-api.
I have created a legacy MVC project, that's why I had this package. When I tried to convert .xml configuration to Java, I came across this problem.
Certainly it's not the same as in the question, but it shows up as the first result in google search.
In my case I just had to comment out the javax.servlet:servlet-api dependency as depicted here:
<!-- dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>7.0.47</version>
</dependency>
This looks like the same idea presented here: https://stackoverflow.com/a/30231246/2597758
I am trying to use Weld-SE for dependency injection in a dropwizard application. I can bootstrap Weld and inject in the Application class like so:
public class App extends Application<AppConfig> {
#Inject NameService service;
#Inject RestResource resource;
public static void main(String[] args) throws Exception {
Weld weld = new Weld();
WeldContainer container = weld.initialize();
App app = container.instance().select(App.class).get();
app.run(args);
weld.shutdown();
}
}
I have written a producer method in a separate class for the RestResource and this is also injected fine. However in the resource class the service is not injected:
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public class RestResource {
#Inject NameService service;
#GET
public String test() {
return service.getName();
}
}
Here service is always null. Does anyone know how to make this work?
Dropwizard is using Jersey whose dependency injection is based on HK2 and not CDI. As a consequence you need to have a bridge between the two. This is what the jersey-gf-cdi is for:
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
</dependency>
You only need to have that JAR in the classpath. You can see here a configuration for Jetty here:
https://github.com/astefanutti/cdeye/blob/cd6d31203bdd17262aab12d992e2a730c4f8fdbd/webapp/pom.xml
And hereafter an example of CDI bean injection into JAX-RS resource:
https://github.com/astefanutti/cdeye/blob/cd6d31203bdd17262aab12d992e2a730c4f8fdbd/webapp/src/main/java/io/astefanutti/cdeye/web/BeansResource.java
For DropWizard 0.8.1 and Weld 2.2 the procedure is as follows:
1) Add dependencies to pom.xml:
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-core</artifactId>
<version>2.2.11.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x</artifactId>
<version>2.17</version>
</dependency>
<!-- the following additional dependencies are needed by weld -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
2) Add beans.xml file to src/main/resources/META-INF and add an inclusion filter for application packages. This is especially needed when using the shaded jar - without the filter Weld would scan every class in the shaded jar.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:weld="http://jboss.org/schema/weld/beans">
<weld:scan>
<weld:include name="com.example.**" />
</weld:scan>
</beans>
3) Register Weld's listener in your application class
#Override
public void run(Configuration conf, Environment env) throws Exception {
env.servlets().addServletListeners(new org.jboss.weld.environment.servlet.Listener());
}
I have a Spring 3 MVC app that I am setting up some ajax actions for.
My controller action looks like this:
#RequestMapping(value="add", method=RequestMethod.POST)
#Secured("ROLE_USER")
#ResponseStatus(HttpStatus.CREATED)
public #ResponseBody Plan addPlan(#RequestBody Plan plan, Principal principal) {
//Save the plan
}
When I post the Plan data from my browser the app throws a ClassNotFound exception:
java.lang.ClassNotFoundException: org.joda.time.ReadableInstant not found by jackson-mapper-asl [176]
at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:787)
at org.apache.felix.framework.ModuleImpl.access$400(ModuleImpl.java:71)
at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1768)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
The Plan object itself does not contain any joda-date types. Though it contains a collection of objects that do. Originally I was pulling in the joda-date jar via my DOA jar but the error persists even if I add a direct dependency to my web project's pom.xml. I'm using the joda classes elsewhere in this project without any issue.
Additional information
Here are the relevant dependencies from my web pom.xml:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.3</version>
</dependency>
I somehow came across this question: Apache FTP server is not seeing a logging jar package that exists in the class path
Their solution of setting <class-loader delegate="false"> in glassfish-web.xml seems to have fixed my issues.
I've reported this on Glassfish JIRA https://java.net/jira/browse/GLASSFISH-20808