I using maven web application, framework spring.
Using Netbeans IDE and Tomcat server.
When I run web in netbeans, URL in browser is:
http://localhost:8080/mywebsite
With this URL website cannot read event servlet mapping.
When I change URL to http://localhost:8080/mywebsite/ then It run good.
What is reason for this case? Why my website don't auto add character "/" in URL?
{update}
config.java
public class Config extends WebMvcConfigurerAdapter {
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/html/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/resources/*");
}
}
Initializer
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(Config.class);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
controller
#Controller
public class MyController {
//<editor-fold defaultstate="collapsed" desc="ADMIN">
#RequestMapping(value = "/", method = RequestMethod.GET)
public String login(ModelMap map) {
return "admin/login";
}}
If you open http://localhost:8080/mywebsite, the web app will try to find some index.html file(based on tomcat or http server configuration).
And you mapping is #RequestMapping(value = "/", method = RequestMethod.GET), so it will apply to http://localhost:8080/mywebsite/. If you want to use your controller to handle http://localhost:8080/mywebsite, you can try to use * in your mapping value. It means, for any request, if there is no specific mapping defined, and that default mapping will be applied.
Related
I am trying to implement a rest web service that uses MultipartFile to upload a file using Spring, with java configuration. I do not use Spring Boot and I have commons-fileupload library in my classpath.
I read Spring documentation that says:
you need to mark the DispatcherServlet with a "multipart-config" section in web.xml, or with a javax.servlet.MultipartConfigElement in programmatic Servlet registration, or in case of a custom Servlet class possibly with a javax.servlet.annotation.MultipartConfig annotation on your Servlet class ... Once Servlet 3.0 multipart parsing has been enabled in one of the above mentioned ways you can add the StandardServletMultipartResolver to your Spring configuration
Hence I added this bean to my AppConfig class:
#Bean
public StandardServletMultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
and annotated the class with MultipartConfig:
#EnableWebMvc
#MultipartConfig(maxFileSize = 5120)
public class AppConfig extends WebMvcConfigurerAdapter{
...
}
but I get this exception when I call the service:
Caused by: org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.UnsupportedOperationException: SRVE8020E: Servlet does not accept multipart request
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:111)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:85)
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:76)
at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:112)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
at [internal classes]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
... 1 more
Caused by: java.lang.UnsupportedOperationException: SRVE8020E: Servlet does not accept multipart request
at com.ibm.ws.webcontainer.srt.SRTServletRequest.prepareMultipart(SRTServletRequest.java:3657)
at [internal classes]
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:92)
If I use CommonsMultipartResolver instead of StandardServletMultipartResolver I get the same error.
This is how I initialize my application:
public class AppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
context.setServletContext(servletContext);
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("CharacterEncodingFilter", characterEncodingFilter);
characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
}
}
I also tried add a MultipartFilter but with no luck.
MultipartFilter multipartFilter = new MultipartFilter();
FilterRegistration.Dynamic multipart = servletContext.addFilter("multipartFilter", multipartFilter);
multipart.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
Is this necessary? What am I doing wrong? I think I read the whole internet searching for a solution but they all use spring boot with MultipartConfigElement and MultipartConfigFactory. Maybe the problem is the way I consume the service?
This is my controller method:
#RequestMapping(value = "/upload", method = RequestMethod.POST, consumes = "multipart/form-data" )
public Long uploadAttachment(#RequestParam("cn") String callerName, #RequestParam("cs") String callerService, #RequestParam("file") MultipartFile file)
and this is how i consume it:
File file = new File("C:\\Users\\cte0289\\Documents\\Email\\document.docx");
RestTemplate rest = new RestTemplate();
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("cn", callerName);
map.add("cs", callerService);
map.add("file", file);
Long response = rest.postForObject(url + "/upload", map, Long.class);
Please help I don't know what else to do.
I think you might want to try something like this:
public class AppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
context.setServletContext(servletContext);
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
dispatcher.setMultipartConfig(getMultipartConfigElement());
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("CharacterEncodingFilter", characterEncodingFilter);
characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
}
private MultipartConfigElement getMultipartConfigElement(){
MultipartConfigElement multipartConfigElement = new MultipartConfigElement("C:/tmp", 1024*1024*5, 1024*1024*5*5, 1024*1024);
return multipartConfigElement;
}
}
The correct way to configure Spring project to handle file upload with java configuration is this:
If you want to configure it with Commons FileUpload library you have only to include this bean in your Configuration class and add the jar in your classpath
#Bean
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(5242880); // set the size limit
return resolver;
}
if you want to configure the project with Servlet 3.0, as #AlieneilA said you have to set the MultipartConfig element in dispatcher servlet:
dispatcher.setMultipartConfig(new MultipartConfigElement("C:/tmp", 1024*1024*5, 1024*1024*5*5, 1024*1024));
and include this bean in configuration class (AppConfig in my case):
#Bean
public StandardServletMultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
I was wrong in the way i inserted the file into the LinkedMultiValueMap. I had to use a FileSystemResource:
File file = new File("C:\\document.doc");
RestTemplate rest = new RestTemplate();
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("param1", param1);
map.add("param2", param2);
map.add("file", new FileSystemResource(file));
Long response = rest.postForObject(url, map, Long.class);
or a MockMultipartFile as suggested by this answer: https://stackoverflow.com/a/38270420/6503002
In this case include spring mock as dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-mock</artifactId>
<version>2.0.8</version>
</dependency>
In case anyone is extending AbstractAnnotationConfigDispatcherServletInitializer class for web application initialization configuration, below simple configuration will enable MultiPart Feature -
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected void customizeRegistration(Dynamic registration) {
MultipartConfigElement multiPart = new MultipartConfigElement("C:/temp/",
1024 * 1024 * 5, 1024 * 1024 * 10, 1024 * 1024 * 3);
registration.setMultipartConfig(multiPart);
}
}
I'm getting this error when trying to post JSON data from angularjs controller to SpringMVC controller. I've tried a lot of solutions posted here and some other stuff available on the net as well. I already have the jackson library in my classpath. And also I'm not using maven because of internet issues.
SpringMVC Controller
#Controller
public class MainController {
#RequestMapping("/")
public String index() {
return "index";
}
#RequestMapping(value = "/employee", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
String saveEmployee(#RequestBody Employee employee) {
//Will do some stuff here.
System.out.println("INSIDE CONTROLLER");
StringBuilder json = new StringBuilder();
return json.toString();
}
}
AngularJS Controller
app.controller('saveEmployeeCtrl', function ($scope, $http) {
$scope.employee = {};
$scope.saveEmployee = function () {
$http({
method: 'POST',
url: 'employee',
data: $scope.employee,
headers:{'Accept':'application/json', 'Content': 'application/json'}
}).success(function(data){
console.log('something nice');
});
};
});
WebConfig
#EnableWebMvc
#Configuration
#ComponentScan("springmvc.com.")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webapp/resources/static/app/**")
.addResourceLocations("/webapp/resources/static/app/");
registry.addResourceHandler("/webapp/resources/static/lib/**")
.addResourceLocations("/webapp/resources/static/lib/");
registry.addResourceHandler("/webapp/resources/static/js/**")
.addResourceLocations("/webapp/resources/static/js/");
registry.addResourceHandler("/webapp/resources/static/css/**")
.addResourceLocations("/webapp/resources/static/css/");
registry.addResourceHandler("/webapp/webapp/resources/static/views/**")
.addResourceLocations("/webapp/webapp/resources/static/views/");
registry.addResourceHandler("/webapp/resources/static/**")
.addResourceLocations("/webapp/resources/static/");
}
#Override
public void configureContentNegotiation(
ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).favorParameter(true)
.parameterName("mediaType").ignoreAcceptHeader(true)
.useJaf(false).defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
}
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
WebAppInitializer
public class WebAppInitializer implements WebApplicationInitializer {
private static final String CONFIG_LOCATION = "springmvc.com.config";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("***** Initializing Application for " + servletContext.getServerInfo() + " *****");
// Create ApplicationContext
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.setConfigLocation(CONFIG_LOCATION);
// Add the servlet mapping manually and make it initialize automatically
DispatcherServlet dispatcherServlet = new DispatcherServlet(applicationContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("mvc-dispatcher", dispatcherServlet);
servlet.addMapping("/");
servlet.setAsyncSupported(true);
servlet.setLoadOnStartup(1);
}
}
You are sending header "Content" but you should send "Content-Type"
Do you send exactly the same fields in JSON as there are in Employee class, check if there are no additional fields, because Jackson has setting that it fail if unrecognized field is set. And there are some resolutions for this issue (like annotation on your class or change this setting)
Most important is what appear in the log file of your server application. What exception is raised as a cause of this http status. So i the solutions above not helping you, please check logs (maybe increase log level for spring) and post it here.
UPDATE:
I have few additional questions:
has your Employee class got default (non args) constructor or maybe you create only constructor with arguments? Could you post your Employee class.
Do you have any logger attached to your project, is there anything in log file, (if there is, please post it)?
There are similar topics, but they all use xml configuration files. The reason why I'm writing this question is that I'm using annotations.
I experience problems running my app:
getting “WARN org.springframework.web.servlet.PageNotFound - No
mapping found for HTTP request with URI …” when trying to setup
Spring servlet
getting error 404 when trying to run it on server
Here is my code (package and imports are skipped):
1) initializer
public class WebInitializer implements WebApplicationInitializer{
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx =
new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet =
servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
2) app config
#Configuration
#ComponentScan("ua.kiev.prog")
#EnableWebMvc
public class AppConfig {
#Bean
public EntityManager entityManager() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("AdvJPA");
return emf.createEntityManager();
}
#Bean
public AdvDAO advDAO() {
return new AdvDAOImpl();
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
resolver.setOrder(1);
return resolver;
}
#Bean
public CommonsMultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
}
3) controller
#Controller
#RequestMapping("/Advertisement")
public class MainController {
#Autowired
private AdvDAO advDAO;
#RequestMapping("/")
public ModelAndView listAdvs() {
return new ModelAndView("index", "advs", advDAO.list());
}
#RequestMapping(value = "/add_page", method = RequestMethod.POST)
public String addPage(Model model) {
return "add_page";
}
#RequestMapping(value = "/search", method = RequestMethod.POST)
public ModelAndView search(#RequestParam(value="pattern") String pattern) {
return new ModelAndView("index", "advs", advDAO.list(pattern));
}
// more code goes here
}
The controller is mapped to /Advertisement, so app should be available at URL localhost:8080/Advertisement/ but it isn't. When I change mapping in annotation to "/" - it becomes available at localhost:8080/Advertisement/. How can it be?
And when I change it back to "/Advertisement" - the same probleb accurs (error 404 and exception "No mapping found for HTTP request with URI …")
So, where I've made a mistake in my code?
Or maybe the problem is in Eclipse/TomCat/Maven?
Source - https://github.com/KostyantynPanchenko/prog.kiev.ua.lesson09.adv
You should change mapping
#Controller
#RequestMapping("/")
public class MainController {
#Autowired
private AdvDAO advDAO;
#RequestMapping("/Advertisement")
public ModelAndView listAdvs() {
return new ModelAndView("index", "advs", advDAO.list());
}
The mistake that a mapper used the value from the annotation to match the request URL, and it can't match the last slash. Note, it should not happen in the above code.
How are you running the application? Atleast in tomcat each deployed application is served from specific context path. Context path is determined from the base file name, more on that here.
So if you're deploying Advertisement.war all requests to the app will be served from localhost:8080/Advertisement/ even though you're declaring the DispatcherServlet and Controller to /
Webapp needs to serve static content and process rest calls on the seperate path.
In config I have registered ResourceHttpRequestHandler and Dispatcher Servlet:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/index.html").addResourceLocations("index.html");
}
#Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet);
registration.setLoadOnStartup(1);
registration.addUrlMappings("/rest/*");
return registration;
}
#Bean(name = "dispatcherServlet")
public DispatcherServlet dispatcherServlet(WebApplicationContext context) {
return new DispatcherServlet(context);
}
But the problem is that reource handler is not invoked if dispatcher servlet is registered, if I remove dispatcher servlet resource serving works.
How to get around this problem?
Maybe I should serve static content also with dispatcher servlet?
In some methods from the controllers in my spring application, I have methods which return a String value to the view, like this example:
#RequestMapping(value="cadastra_campo", method=RequestMethod.GET)
public String cadastra_campo(#ModelAttribute("username") String username, #RequestParam("nome") String campo) {
if(key.temAutorizacao(key.getUsuarioByUsername(username).getId())) {
if(key.cadastra(campo))
return "yes";
else
return "not";
}
else {
return "no_permit";
}
}
But, monitoring the value received by the views, through the browser's console, I realize that all of them are trying reach out pages like /jst/yes.jsp.
this output is read in the view by jquery functions like that:
$("#incluir_campo").on("click", function () {
$.ajax({
type: "GET",
url: "<c:out value="${pageContext.request.contextPath}/key/cadastra_campo"/>",
data: {nome: $("input[name=nome_campo]").val() }
}).done(function(data){
if(data=="yes") {
var newRow = $("<tr>");
cols = 'td> <input type="text" name="${item_key.nome}" value="${item_key.nome}"> </td>';
cols += '<td> <button type="button" id="excluir_campo_${item_campo.id}" class="btn btn-link">Excluir</button> </td>';
newRow.append(cols);
$("table.campos").append(newRow);
$("input[name=nome_campo]").reset();
}
else {
alert("erro ao incluir campo");
}
}).fail(function(){
alert("falha ao incluir campo");
});
});
I am using a java configuration in replacement to files web.xml and spring-servlet.xml, through this classes:
WebAppInitializer.java
#Order(value=1)
public class WebAppInitializer implements WebApplicationInitializer {
#SuppressWarnings("resource")
#Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(WebAppConfig.class);
// Manage the lifecycle of the root application context
//container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
WebAppConfig.java
#EnableWebMvc
#EnableTransactionManagement(mode=AdviceMode.PROXY, proxyTargetClass=true)
#ComponentScan(value="com.horariolivre")
#Configuration
public class WebAppConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/bootstrap/**").addResourceLocations("/bootstrap/").setCachePeriod(31556926);
registry.addResourceHandler("/extras/**").addResourceLocations("/extras/").setCachePeriod(31556926);
registry.addResourceHandler("/jquery/**").addResourceLocations("/jquery/").setCachePeriod(31556926);
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Someone knows how to do for my views receive correctly a String value, instead of try reach a jsp page?
If you don't provide a ViewResolver in your context configuration available to the DispatcherServlet, it will use a default. That default is an InternalResourceViewResolver.
When your #RequestMapping handler method returns a String, Spring uses ViewNameMethodReturnValueHandler to handle it. It will set the returned String value as the request's view name. Down the line, Spring's DispatcherServlet will use the InternalResourceViewResolver to resolve a view based on the provided name. This will be a JSP. It will then forward to that JSP.
If you want to return the handler method's String return value as the body of the HTTP response, annotate the method with #ResponseBody. Spring will use RequestResponseBodyMethodProcessor to write the value to the HttpServletResponse OutputStream.