Force 404 error when extension is added to URL - spring

I need some help with URL mapping, in my code when i go to:
http://localhost:8080/register.asdf
http://localhost:8080/register.asddsdsd etc.
it always returns http://localhost:8080/register but I want to make it 404 NOT FOUND.
How can I fix this?
public class WebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(Config.class);
ctx.setServletContext(servletContext);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
#Controller
public class UserController {
#RequestMapping(path = "/register", method = RequestMethod.GET)
public String registerGet(Model model) {
return "register";
}
EDIT : i added following code in Config.java and solved thanks.
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}

You can restrict your mapping changin the #RequestMapping or the servlet.mapping.
Change RequestMapping:
#RequestMapping(path = "/register.htm", method = RequestMethod.GET)//for example
Or servlet.mapping:
servlet.addMapping("*.htm");
EDIT:
If you are using Spring 4.X you can use this:
<mvc:annotation-driven>
<mvc:path-matching suffix-pattern="false" />
</mvc:annotation-driven>

From docs use below config to restrict the unwanted extensions
<mvc:annotation-driven>
<mvc:path-matching suffix-pattern="false" />
</mvc:annotation-driven>

Related

How can I register a servlet with Spring Boot?

This code don't work
I have a web.xml that needs to be translated into a spring boot
<servlet>
<servlet-name>page-resolver</servlet-name>
<servlet-class>com.bk.ForwardServlet</servlet-class>
<init-param>
<param-name>page</param-name>
<param-value>/index.jsp</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>page-resolver</servlet-name>
<url-pattern>/index.html</url-pattern>
<url-pattern>/login</url-pattern>
<url-pattern>/qmgr/*</url-pattern>
</servlet-mapping>
and this class
#WebServlet
public class ForwardServlet extends HttpServlet {
private String page;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
page = config.getInitParameter("page");
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher(page).forward(req, resp);
}
}
I wrote code that registers this bean but it doesn't work and I don't understand why
#Configuration
public class ConfigureWeb implements ServletContextInitializer {
private void registerServlet(ServletContext servletContext) {
ServletRegistrationBean serviceServlet =
new ServletRegistrationBean(new ForwardServlet(), "/index.html","/login","/qmgr/*");
serviceServlet.addUrlMappings("/index.jsp");
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerServlet(servletContext);
}
}
First of all check and verify that all your resources are being kept in the correct directory.For spring-boot the jsp pages are to be kept in the directory src->main->webapp->WEB-INF->view->*.jsp .
You should have the following dependencies added in pom to compile the jsp properly when using embedded tomcat :
<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- To compile JSP files -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
Now we need to tell spring where the jsp files reside, we can have two approaches for this :
Add entries in application.properties
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
Here we can specify the folder where the jsp files are to be expected, as well as define the view.
or
Configure InternalResourceViewResolver to serve JSP pages
#Configuration
#EnableWebMvc
#ComponentScan
public class MvcConfiguration extends WebMvcConfigurerAdapter
{
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
registry.viewResolver(resolver);
}
}
Now for registering servlets :
ServletRegistrationBean is used to register Servlets in Servlet 3.0 + container. We need to create a bean of ServletRegistrationBean in our JavaConfig. Find some methods of ServletRegistrationBean used to configure a Servlet.
setServlet(): Sets the servlet to be registered.
addUrlMappings(): Add URL mappings for the Servlet.
setLoadOnStartup: Sets priority to load Servlet on startup.
Suppose we have two Servlets as HelloCountryServlet and HelloStateServlet then we will register them with Spring Boot using ServletRegistrationBean as following :
#Configuration
public class WebConfig {
#Bean
public ServletRegistrationBean<HttpServlet> countryServlet() {
ServletRegistrationBean<HttpServlet> servRegBean = new ServletRegistrationBean<>();
servRegBean.setServlet(new HelloCountryServlet());
servRegBean.addUrlMappings("/country/*");
servRegBean.setLoadOnStartup(1);
return servRegBean;
}
#Bean
public ServletRegistrationBean<HttpServlet> stateServlet() {
ServletRegistrationBean<HttpServlet> servRegBean = new ServletRegistrationBean<>();
servRegBean.setServlet(new HelloStateServlet());
servRegBean.addUrlMappings("/state/*");
servRegBean.setLoadOnStartup(1);
return servRegBean;
}
}
For every Servlet we create a ServletRegistrationBean bean.
And the servlet class will look like :
public class HelloCountryServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException{
doGet(request,response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h3>Hello India!</h3>");
}
}
This is one approach.
Another method to register servlets in spring-boot is using annotations : #ServletComponentScan and #WebServlet. #ServletComponentScan in Spring Boot will scan Servlets annotated with #WebServlet, Filters annotated with #WebFilter and Listeners annotated with #WebListener.The annotation #ServletComponentScan is used on JavaConfig at class level. #ServletComponentScan scans Servlets, Filters and Listeners only using an embedded web server. Find the Servlets annotated with #WebServlet.
So the earlier HelloCountryServlet servlet can be provided as :
#WebServlet(urlPatterns = "/country/*", loadOnStartup = 1)
public class HelloCountryServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException{
doGet(request,response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h3>Hello India!</h3>");
}
}
and provide the ServletComponentScan annotation like :
#ServletComponentScan
#SpringBootApplication
public class SpringBootAppStarter {
public static void main(String[] args) {
SpringApplication.run(SpringBootAppStarter.class, args);
}
}
If you are not required to register a servlet, you could add the forwarding to the ViewControllerRegistry
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index.html").setViewName("forward:/index.jsp");
registry.addViewController("/login").setViewName("forward:/index.jsp");
registry.addViewController("/qmgr/**").setViewName("forward:/index.jsp");
}
}
You could combine the three addViewControllers into one using AntPathMatcher patterns
Map a view controller to the given URL path (or pattern) in order to
render a response with a pre-configured status code and view.
Patterns like "/admin/**" or "/articles/{articlename:\w+}" are
allowed. See AntPathMatcher for more details on the syntax.
Personally I think separating them is more readable

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 :)

Extending the JSTL View class

I am extending the JSTL view class to implement my own view resolver. But, I am having the problem. Look into my code:
public class TestView extends JstlView {
private String fo_suffix = "_jo";
public void setUrl(String url)
{
//We need to change the inputed url to add a prefix for fo
super.setUrl(url.replace("\\.jsp", fo_suffix+ ".jsp"));
}
public void render(Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
final StringWriter xmlfo = new StringWriter();
HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(
response) {
#Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(xmlfo);
}
};
super.render(model, request, wrapper);
In the above code, when i am debugging, the control never comes to the setUrl method. So the url is always null in the internal RequestDispatcher.
Please help me to resolve the issue.
Dont forget to put TestView in "myServletName"-servlet.xml
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="test.TestView"/>
....

Can spring mvc trim all strings obtained from forms?

I know struts2 default config will trim all strings obtained from forms.
For example:
I type " whatever " in a form and submit, I will get "whatever" The string has been auto trimmed
Does spring mvc have this function too? THX.
Using Spring 3.2 or greater:
#ControllerAdvice
public class ControllerSetup
{
#InitBinder
public void initBinder ( WebDataBinder binder )
{
StringTrimmerEditor stringtrimmer = new StringTrimmerEditor(true);
binder.registerCustomEditor(String.class, stringtrimmer);
}
}
Testing with an MVC test context:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration
public class ControllerSetupTest
{
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup ( )
{
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void stringFormatting ( ) throws Exception
{
MockHttpServletRequestBuilder post = post("/test");
// this should be trimmed, but only start and end of string
post.param("test", " Hallo Welt ");
ResultActions result = mockMvc.perform(post);
result.andExpect(view().name("Hallo Welt"));
}
#Configuration
#EnableWebMvc
static class Config
{
#Bean
TestController testController ( )
{
return new TestController();
}
#Bean
ControllerSetup controllerSetup ( )
{
return new ControllerSetup();
}
}
}
/**
* we are testing trimming of strings with it.
*
* #author janning
*
*/
#Controller
class TestController
{
#RequestMapping("/test")
public String test ( String test )
{
return test;
}
}
And - as asked by LppEdd - it works with passwords too as on the server side there is no difference between input[type=password] and input[type=text]
register this property editor:
org.springframework.beans.propertyeditors.StringTrimmerEditor
Example for AnnotionHandlerAdapter:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
...
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="propertyEditorRegistrar">
<bean class="org.springframework.beans.propertyeditors.StringTrimmerEditor" />
</property>
</bean>
</property>
...
</bean>
You can also use Spring's conversion service, which has the added benefit of working with <mvc:annotation-driven/> and with Spring Webflow. As with the other answers, the major downside is that this is a global change and can't be disabled for certain forms.
You'll need a converter to do the trimming
public class StringTrimmingConverter implements Converter<String, String> {
#Override
public String convert(String source) {
return source.trim();
}
}
Then define a conversion service that knows about your converter.
<bean id="applicationConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="mypackage.util.StringTrimmingConverter"/>
</list>
</property>
</bean>
and tie that in to mvc.
<mvc:annotation-driven conversion-service="applicationConversionService"/>
If you use Spring Webflow then it require a wrapper
<bean id="defaultConversionService" class="org.springframework.binding.convert.service.DefaultConversionService">
<constructor-arg ref="applicationConversionService"/>
</bean>
and a setting on your flow builder
<flow:flow-builder-services id="flowBuilderServices" conversion-service="defaultConversionService" development="true" validator="validator" />
Just customized the above code in order to adjust to Spring Boot, if you want to explicit trim function for some fields in the form, you can show them as below:
#Component
#ControllerAdvice
public class ControllerSetup {
#InitBinder({"dto", "newUser"})
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
binder.registerCustomEditor(String.class, "userDto.username", new StringTrimmerEditor(false));
binder.registerCustomEditor(String.class, "userDto.password", new DefaultStringEditor(false));
binder.registerCustomEditor(String.class, "passwordConfirm", new DefaultStringEditor(false));
}
}
You can user a Spring-MVC Interceptor
public class TrimInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Enumeration<String> e = request.getParameterNames();
while(e.hasMoreElements()) {
String parameterName = e.nextElement();
request.setParameter(parameterName, request.getParameter(parameterName).trim());
}
return true;
}
And set up your HandlerMapping interceptors property
<bean id="interceptorTrim" class="br.com.view.interceptor.TrimInterceptor"/>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" p:interceptors-ref="interceptorTrim"/>
}
Or use a Servlet Filter
first,trim requestparam which is String,you can create a class and implimplements WebBingdingInitializer
#ControllerAdvice
public class CustomWebBindingInitializer implements WebBindingInitializer {
#InitBinder
#Override
public void initBinder(WebDataBinder webDataBinder, WebRequest webRequest) {
webDataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
}
please use componentScan make this Class to be a Spring Bean.
But, I don't know how to trim the String value in requestBody JSON data.

Resources