I recently migrated to Spring boot. I used Spring MVC before. When I go to a site after the application starts, this throws 404 page not found. The controller handles the request, but for some reason does not find the jsp page.
My Application.java:
package com.myapp.webapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication(scanBasePackages = "com.myapp")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.properties
# Spring MVC configuration
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.datasource.url=jdbc:mysql://us-cdbr-iron-east-05.cleardb.net/heroku_4663e71bc0d567a?reconnect=true
spring.datasource.username=bb1a6d3ce29ada
spring.datasource.password=******
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/socialnet?autoReconnect=true&useSSL=false
#spring.datasource.username=root
#spring.datasource.password=123
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
debug=true
And controller for example
package com.myapp.webapp;
//imports
#Controller
#SessionAttributes({"accountInSession", "base64Photo"})
public class MainController {
private static final Logger logger = LoggerFactory.getLogger(MainController.class);
#Autowired
private AccountService accountService;
#Autowired
private AuthenticationTrustResolver authenticationTrustResolver;
#RequestMapping(value = {"/login", "/"})
public ModelAndView loginPage(#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout,
#RequestParam(value = "noLogin", required = false) String noLogin) {
ModelAndView modelAndView = new ModelAndView("/login");
if (error != null) {
modelAndView.addObject("error", "Incorrect mail and/or password");
//modelAndView.setViewName("login");
}
if (logout != null) {
modelAndView.addObject("msg", "You've been logged out successfully!");
//modelAndView.setViewName("login");
}
if (noLogin != null) {
modelAndView.addObject("error", "Please log in to view this page");
}
if (!isCurrentAuthenticationAnonymous()) {
//modelAndView.setViewName("login");
modelAndView.setViewName("redirect:/account");
return modelAndView;
}
return modelAndView;
}
#RequestMapping("/test")
public String test() {
return "redirect:/registration";
}
}
For example if I go to http://localhost:8080/test controller redirected me to http://localhost:8080/registration
I used a multi module maven project with models: common(for models), dao, service and webapp.
So controllers located in
java/com/myapp/webapp/controllers
Jsp pages located in
src/main/webapp/WEB-INF/jsp
And path to files:
java/com/myapp/Application.java
src/main/resources/application.properties
And structure of wepapp module
You need to provide your implementation of view resolver using WebMvcConfigurer.
WebMvcConfigurer has replaced the old, deprecated WebMvcConfigurerAdapter.
#EnableWebMvc
#Configuration
#ComponentScan
public class CustomWebConfig implements WebMvcConfigurer {
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
}
You need to provide prefix(/WEB-INF/jsp/) and suffix(.jsp) explicitly as registry.jsp()method takes default prefix as /WEB-INF/ and suffix as .jsp.
Refer Spring Framework: ViewResolverRegistry class
I have solve this problem. I move all jsp files from src/main/wepapp/WEB-INF/jsp/
to src/main/resources/META-INF/resources/WEB-INF/jsp/. I have no idea why it not works before, but now it works
Related
I had the error "Access to XMLHttpRequest at 'http://localhost:8081/products/getPro' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource" while I have added the annotation #CrossOrigin("*") in my spring boot application
#RestController
#RequestMapping("/products")
#CrossOrigin("*")
public class ProductController {
#Autowired
private ProductService productService;
#PostMapping(value = "/getPro", consumes = {"application/json"}, produces =
{"application/json"})
public ResponseEntity<?> getPro(#RequestBody Product product){
return this.productService.getPro(product);
}
In my Frontend I have :
export class ProductService {
public productModel : Product
private baseUrl = 'http://localhost:8081';
constructor(private http:HttpClient) { }
getPro () {
return this.http.post<Product>(this.baseUrl + "/products/getPro",
JSON.stringify(this.productModel));
}
}
Can anyone help me ?
PS :I am using this application like a feign client I mean in reality I am calling another application with FeignClient ! It can be the problem ?
I will suggest you to get rid of #crossOrigin.
You can do following in your config file
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");// Your allowed paths here
}
}
I will recommend you to move that all to angular only by using reverse proxy.
{
"/api": {
"target": "http://localhost:8081",
"secure": false
}
}
See github project here. https://github.com/vohra01/parking-demo-SG/blob/master/IdeaProjects/parking-demo/parking-ui-app/proxy.conf.json
I've a spring boot web application that can serve files from a static file location in server.
I've specified the location in properties file and using it to configure the ResourceHandlerRegistry.
#SpringBootApplication
public class MyWebApplication {
#Value("${targetdirectory}")
private String targetDirectory;
#Bean
WebMvcConfigurer configurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
targetDirectory = StringUtils.appendIfMissing(targetDirectory, "/", "/");
targetDirectory = StringUtils.prependIfMissing(targetDirectory, "file:/", "file:/");
registry.addResourceHandler("/resourcetarget/**").addResourceLocations(targetDirectory);
}
};
}
public static void main(String[] args) {
SpringApplication.run(MyWebApplication.class, args);
}
}
Everything works as expected. Now I have to dynamically set the resource location based on user input.
After the application is loaded, the user triggers an HTTP post request where he can specify the directory by which can be used as the resource location.
So after that any requests to the /resourcetarget/** should be mapped to the directory which the user specified. Following is the controller I have.
#RestController
#RequestMapping(value = "api/locations", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class MyController {
#PostMapping
public ResponseEntity<Object> handleLocationSet(#RequestBody LocationDTO locationDto) {
String newFileLocation = locationDto.getLocation();
// How do I update the ResourceHandlerRegistry mapping for /resourcetarget/**
// with the new location received here?
return ResponseEntity.ok();
}
}
How can I update the mapping for this dynamic location for a static resource url. Please help
Controller needs uses .htm extensions for all handlers, including JSON REST endpoints. How should I test for REST endpoints?
Problem:
I cannot disable suffix interpretation and I am getting 406 "Could not find acceptable representation"
Tried attempts:
I reviewed posts on stackoverflow related to 406, but could not find relevant one to the case where 'htm' suffix is used in tests. When you remove '.htm' suffix from both Controller and Test - the test is passing.
Here is controller with /changePassword.htm endpoint:
#Controller
public class MainController {
public static class ResultBean {
private final String result;
public String getResult() {
return result;
}
public ResultBean(String result) {
this.result = result;
}
}
#RequestMapping(value="/changePassword.htm", method= RequestMethod.POST, produces = { "application/json" })
public #ResponseBody ResultBean changePassword (
#RequestParam("username") String username, #RequestParam("password") String password) {
return new ResultBean("OK");
}
}
And here is the test with configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { HomeControllerTest.Config.class })
public class HomeControllerTest {
#InjectMocks
private MainController controller = new MainController();
private MockMvc mvc;
#Configuration
#EnableWebMvc
public static class Config extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false)
.favorParameter(true)
.parameterName("mediaType")
.ignoreUnknownPathExtensions(true)
.ignoreAcceptHeader(false)
.useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON);
}
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(controller)
.build();
}
#Test
public void shouldPassChangePasswordBean() throws Exception {
mvc.perform(post("/changePassword.htm")
.accept("*/*")
.param("username", "example")
.param("password", "abcdef")
)
.andExpect(status().isOk()); // Test produces 406 instead of 200
}
}
Any idea?
On newer version of Spring (4+ I think), mime type is determined from suffix first.
So If you use a .htm suffix, Spring will default to produce HTML even if you don't want to.
One way to bypass this is to use a filter that rewrite URL. For instance tuckey URL rewriter filter
With this, you can set some rules like:
/my/page/that/return/json.htm is rewriten to /my/page/that/return/json so that Spring can produce data according to the Accept header.
with Spring 5, try changing your URL of your web service to .json! that is the right fix. great details here http://stick2code.blogspot.com/2014/03/solved-orgspringframeworkwebhttpmediaty.html
I'm building a RESTful API and have a Spring REST Controller (#RestController) and an annotation-based configuration. I'd like to have my project's welcome-file be a .html or .jsp file with the API documentation.
In other web projects I would place a welcome-file-list in my web.xml, but in this particular project I can't seem to get it to work (preferrably using Java and annotations).
This is my WebApplicationInitializer
public class WebAppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(ApplicationConfig.class);
context.setServletContext(servletContext);
ServletRegistration.Dynamic dynamic = servletContext.addServlet("dispatcher",
new DispatcherServlet(context));
dynamic.addMapping("/");
dynamic.setLoadOnStartup(1);
}
}
This is my WebMvcConfigurerAdapter
#Configuration
#ComponentScan("controller")
#EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {
#Bean
public Application application() {
return new Application("Memory");
}
}
And this is a small part of my REST Controller
#RestController
#RequestMapping("/categories")
public class CategoryRestController {
#Autowired
Application application;
#RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<Integer, Category>> getCategories(){
if(application.getCategories().isEmpty()) {
return new ResponseEntity<Map<Integer, Category>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<Map<Integer, Category>>(application.getCategories(), HttpStatus.OK);
}
}
So far I've tried:
Adding just a web.xml with a <welcome-file-list> with a <welcome-file>. (no luck there)
Moving the #RequestMapping("/categories") in the Controller from the class level to all of the methods, and adding a new method with #RequestMapping("/"), which returns either a String or a ModelAndView with the view name. (the former just returned a blank page with the String, for the latter no mapping could be found)
As suggested here: a combination of both, where my web.xml <welcome-file> is "/index", combined with #RequestMapping(value="/index") returning a new ModelAndView("index"), and a ViewResolver in my configuration class. (returns a Warning: No mapping found in DispatcherServlet with name 'dispatcher', even though "/index" is successfully mapped. Manually adding "/index" to the URL successfully resolves it to index.jsp)
When specifying a controller to handle your index page you should use a #Controller not a #RestController. Although the #RestController is a #Controller it doesn't resolve to a view but returns the result as is to the client. When using a #Controller when returning a String it will resolve to the name of a view.
#Controller
public class IndexController {
#RequestMapping("/")
public String index() {
return "index";
}
}
However there is an easier way to configure this and you don't need a controller for it. Configure a view controller. In your configuration class simply override/implement the addViewControllers method.
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
That way you don't even need to create a class for it.
I'm starting an embedded tomcat via spring-boot and want to serve a static index.html page as part of a running application.
But the following does not work:
#SpringBootApplication
public class HMyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
#RestController
public class HomeContoller {
#RequestMapping("/")
public String index() {
return "index";
}
}
src/main/resources/static/index.html
Result: when I call localhost:8080, I just see the word "index", but not my html page. Why?
My fault: I had an additional class with #EnableWebMvc annotation. This somehow messed up the spring-boot autoconfiguration. I removed it and now it works returning index.html.
For me this worked, i am sure there is a better way ( like without .html ).
#RequestMapping("/")
public String index() {
return "index.html";
}
You can use ModelAndView in order to serve static HTML content in spring boot.
#RequestMapping("/")
public ModelAndView home()
{
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index");
return modelAndView;
}
application.properties:-
spring.mvc.view.suffix = .html
HTML File : - src/main/resources/static/index.html
Thats because of #RestController annotation, just removing this annotation works for me.