Request Post not allowed for controller, but get works - spring-boot

I have a spring-boot with a cors. I want set a static page controller,
I want return a static html page for same post/get request.
The get request works, but with the post request i have :
{
"timestamp": 1563296215801,
"status": 405,
"error": "Method Not Allowed",
"message": "Request method 'POST' not supported",
"path": "/test"
}
My code :
#Controller
#RequestMapping("/")
public class StaticPageController implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/test").setViewName(
"test");
}
#RequestMapping(value = "test", method = { RequestMethod.GET,
RequestMethod.POST })
public String test() {
return "test";
}
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("folder/");
resolver.setSuffix(".html");
return resolver;
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
With the post request, my breakpoint in 'return "test";' is fired. But after i have a 405 error...
Any ideas ?

You are facing the issue because along with configuring the GET endpoint for /test , you have also configured the ViewControllerRegistry to return the view test to /test url.
The ViewControllerRegistry is configured whenever you want to serve a static content without the need of a controller. So , try removing that and your controller method should work as expected because by default only GET is supported by ViewControllerRegistry.
Assists with the registration of simple automated controllers pre-configured with status code and/or a view. ViewControllerRegistry
registers view controller.
We need not to create actual controller class when using ViewControllerRegistry. It is used when we just need to map a URL
with a view. addViewController(String urlPath): It adds a view
controller for the given URL.
This method returns ViewControllerRegistration and using ViewControllerRegistration.setViewName() a corresponding view is
mapped. addRedirectViewController(String urlPath, String
redirectUrl): It maps a URL to another URL to redirect on it. It has
been introduced in spring 4.1.
addStatusController(String urlPath, HttpStatus statusCode): It maps a URL with given status code. It has also been introduced in spring
4.1.
Try using :
#Controller
#RequestMapping("/")
public class StaticPageController implements WebMvcConfigurer {
#RequestMapping(value = "test", method = { RequestMethod.GET,
RequestMethod.POST })
public String test() {
return "test";
}
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("folder/");
resolver.setSuffix(".html");
return resolver;
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}

Related

How to link to view file in controller by click view name

A springboot web project,work by idea . in the controller code,I want to click "manage/operate/createCluster" ,then the idea will open the /web-inf/jsp/manage/operate/createCluster.jsp file.
How to achieve or what information can be referenced?
#RequestMapping(value = "createCluster", method = RequestMethod.GET)
public ModelAndView doClusterList(HttpServletRequest request,
HttpServletResponse response, Model model) {
model.addAttribute("activeMenuId","createCluster");
return new ModelAndView("manage/operate/createCluster");
}
If you want just affiche a view without any data to populate you can add a view controller in Your WebMvc config class like :
#Configuration
#EnableWebMvc
#ComponentScan
public class WebConfig implement WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/manage/operate/createCluster").setViewName("manage/operate/createCluster");
}
}
If you want to send data in your view as your example you must just send the view name as String:
#RequestMapping(value = "createCluster", method = RequestMethod.GET)
public String doClusterList(HttpServletRequest request,
HttpServletResponse response, Model model) {
model.addAttribute("activeMenuId","createCluster");
return "manage/operate/createCluster";
}
You should add config of your view Resolver for both cases :
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}

#RestController returning blank

I'm building my first Spring Boot application. But I can't get my requestMapping controller answer properly.
This is my main class:
package com.hello.world;
#SpringBootApplication
public class HelloWorld implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(HelloWorld.class, args);
}
#Override
public void run(String... args) throws Exception {
....
}
}
And this is my RestController:
package com.hello.world.controllers;
#RestController
public class UrlMappingControllers {
#RequestMapping("/hi")
String home() {
return "Hello World!";
}
}
If I take a look at the log I can see the "/hi" mapping:
restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hi]}" onto java.lang.String com.hello.world.controllers.UrlMappingControllers.home()
But when I access: http:localhost:8080/hi I get a blank page, I expected seing the "Hello World" text.
Why am I getting a blank page?
--- Edit ----
I've just realised that I am getting the blank page only when I add a cxf service. I think it is because the #configuration annotation on this class:
package com.hello.world.helloWorld.configuration;
#Configuration
public class CXFConfiguration {
#Bean
public ServletRegistrationBean dispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/services/*");
}
#Bean(name=Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
SpringBus springBus = new SpringBus();
return springBus;
}
#Bean
public Endpoint endpointGreentingService() {
EndpointImpl endpoint = new EndpointImpl(springBus(), new GreetingServiceImpl());
endpoint.getFeatures().add(new LoggingFeature());
endpoint.publish("/GreetingService");
return endpoint;
}
}
Could it be related?
#RestController = #Controller + #ResponseBody which means that when you call your api at http:localhost:8080/hi the body of the response will contain the result of the home() handler, i-e "Hello world".
#RestControllerbehind the scene makes Spring MVC uses a Json Message Converter (by default) and all handler methods inside a class annoted with #RestController will return a JSON, that is why you do not see your text on your browser.
You can use Postman or ARC to test your app. Some web browsers like Firefox shows JSON directly.

Spring custom view resolver

I've tried to change the prefix of the view based on the useragent.
If the request comes from IE then trying to forward it to "legacy" folder otherwise "modern" folder.
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setViewClass(JstlView.class);
internalResourceViewResolver.setSuffix(".jsp");
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
if(request.getHeader("User-Agent").contains("Internet Explorer")){
internalResourceViewResolver.setPrefix("/WEB-INF/views/legacy/");
} else {
internalResourceViewResolver.setPrefix("/WEB-INF/views/modern/");
}
return internalResourceViewResolver;
}
Its not at all working. Can anyone suggest?
Don't hack around in the ViewResolver write a HandlerInterceptor instead.
public class BrowserPrefixHandlerInterceptor extends HandlerInterceptorAdapter {
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
if(request.getHeader("User-Agent").contains("Internet Explorer")){
modelAndView.setViewName("legacy/" + modelAndView.getViewName());
} else {
modelAndView.setViewName("modern/" + modelAndView.getViewName());
}
}
}
Then register is like a regular interceptor.
#Configuration
public YourWebConfiguration extends WebMvcConfigurerAdapter {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new BrowserPrefixHandlerInterceptor());
}
}
Just leave the ViewResolver alone. This will work for each ViewResolver and not just for your own customized version. You might want to make the interceptor a little smarter (check if there is actually a viewName and maybe skip it for certain URLs).

The requested resource is not available when wanna map to .html file

I'm using Spring mvc, and wanna make web app which send some json data to client and client should visualized them using js.
I have some questions:
1-My project have some *.html beside *.jsp file how can I handle both without web.xml. the code that i had written work fine with *.jsp but give "The requested resource is not available." error for mapping html files.
2-As i said My service have to send a list of object in json form to client, when i want to parse the json string on server in *.jsp file with the code like
MyClass data = new Gson().fromJson(MyList.get(0).toString(), listType)
,I face with to many problems, so i decide to do this job in client Side in *.html file, i want to know how should i handle this parsing job when i don't want that client know about the structure my class? OR plz tell if have to share my class with client, how should i send stucture of it to html file?
3-How should i access to data that i created in restapi.jsp on the UserSideApp.html file?
these are some my files:
AppInitializer.java
public class AppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
} }
AppConfig.java
public class AppConfig {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix("");
return viewResolver;
} }
the part of my AppContoller.java
#Controller
#RequestMapping("/")
public class AppController {
#Autowired
HackDataService service;
#RequestMapping(value = "/restapi", method = RequestMethod.GET)
public String jsonAPI(ModelMap model) {
List<HackData> newList = service.findAllNewData();
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json="";
try {
json = ow.writeValueAsString(newList);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
model.addAttribute("List", json);
String newjson = new Gson().toJson(newList);
model.addAttribute("newList", newjson);
return "newTest.jsp";
}
#RequestMapping(value = "/app", method = RequestMethod.GET)
public String htmlapp() {
return "UserSideApp.html";
} }
and my both .html and .jsp files are in "/WEB-INF/views/"
After spending almost a day on first problem, i find the answer of it,
first of all instead of implementing WebApplicationInitializer, I extend AbstractAnnotationConfigDispatcherServletInitializer and for java Configing i extends WebMvcConfigurerAdapter.
Then i create a pages folder in WEB-INF and my codes changes to these:
AppInitializer became like other internet's samples.
AppConfig.java
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.attackmap" })
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/WEB-INF/pages/");
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix("");
return viewResolver;
}
}
AppController.java
#Controller
#RequestMapping("/")
public class AppController {
#RequestMapping(value = { "/", "/info" }, method = RequestMethod.GET)
public String welcome(ModelMap model) {
model.addAttribute("message", "home page with info about site");
return "homepage.jsp";
}
#RequestMapping(value = "/finalapp", method = RequestMethod.GET)
public String test() {
return "redirect:/pages/final.htm";
} }
there was another way
Creating a "resources" directory in "src/main/webapp"
add bellow cod in AppConfig.java
registry.addResourceHandler("/WEB-INF/views/resources/*.html").addResourceLocations("/resources/");
and for viewResolving use the code like bellow:
#RequestMapping(value = "/newapp", method = RequestMethod.GET)
public String test2() {
return "/resources/UserSideAppNew.html";
}
but still my two other questions are unsolved, the main problem was first one but if you know sth, about these two plz tell me about them

Spring static resource mapping does not work

i am trying to create a Spring MVC application with security included. All configuration is made in code, no XML-s. First, i have my WebApplicationInitializer, mapping all requests to my dispatchservlet:
public class DBCAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(DBCConfiguration.class);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
servlet.setMultipartConfig(new MultipartConfigElement("", 1024*1024*5, 1024*1024*5*5, 1024*1024));
}
Also there is a config file:
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "our.dbc")
public class DBCConfiguration extends WebMvcConfigurerAdapter {
private static final Logger log = Logger.getLogger(DBCConfiguration.class);
#Bean
public InternalResourceViewResolver getInternalResourceViewResolverJsp(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
viewResolver.setOrder(0);
log.info("#### Internal view resolver 0 called...");
return viewResolver;
}
#Bean
public StandardServletMultipartResolver multipartResolver(){
log.info("#### Multipart resolver called...");
return new StandardServletMultipartResolver();
}
// #Override
// public void addResourceHandlers(final ResourceHandlerRegistry registry) {
// registry.addResourceHandler("/resources/**")
// .addResourceLocations("/resources/");
//
// }
//
// #Override
// public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// configurer.enable();
// }
}
As you can see, i have tried both addResourceHandler and configureDefaultServletHandling, but none of those worked. Problem is that all request by default, with lowest priority end up returing welcome page (so if bad address requested, welcome is returned :), so that instead of getting the css client gets back to welcome page:
#Controller
public class FileUploadController {
private static final Logger LOG = Logger.getLogger(FileUploadController.class);
private static final String FORM = "form";
private static final String WELCOME = "welcome";
private static final String DENIED = "accessDenied";
private static final String UPLOADED_REDIRECT = "redirect:/uploaded";
#Autowired
FileUploadService uploadService;
#RequestMapping(value = "/**", method = RequestMethod.GET)
public String getWelcome() {
return WELCOME;
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage() {
LOG.info("#### /login called..." );
return "login";
}
#RequestMapping(value = { "/uploaded" }, method = RequestMethod.GET)
public String getUploaded() {
LOG.info("#### /uploaded called..." );
return "uploaded";
}
.
.
.
As i said, i also have security configured, but with default container servlet serving static resources, it whould not have to be changed. Anyway, i tried also to add permitall to resources, but no success. Anyway if i disable security it does not work either, so security is not the problem.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/welcome").permitAll()
.antMatchers("/form").access("hasRole('ADMIN')and hasRole('USER')")
.
.
.
But no chances. If i type http://localhost:8080/SpringMVC/resources/app.css instead of getting the stylesheet, browser gets back to welcome page.
Any suggestions? Any help whould be appreciated :)

Resources