I reading Spring in Action and trying to repeat code from book. Its work fine when i use html instead of jsp. But problem is that, when i start server, then i see source code of jsp insted of web-page.
My source code is:
WebConfig
package spittr.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
#ComponentScan(value = "spittr.web")
public class WebConfig
extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver =
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
RootConfig
package spittr.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#Configuration
#ComponentScan(basePackages={"spittr"},
excludeFilters={
#Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)
})
public class RootConfig {
}
SpittrWebAppInitializer
package spittr.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
}
Application
package spittr.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Created by vadim on 10/5/16.
*/
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
HomeController
package spittr.web;
import static org.springframework.web.bind.annotation.RequestMethod.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class HomeController {
#RequestMapping(value="/", method=GET)
public String home() {
return "home";
}
}
Structure of project is image structure
I fixed it. To run my program just need to detete Application and run program with TomCat(with exploded artifact).
Related
I am trying to get my OrderController to work, but MVC can't seem to find it. Does anyone know why this happens?
Initializer class. The getServletMapping method keeps notifying me about Not annotated method overrides method annotated with #NonNullApi
package configs;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Config.class};
}
#Override
protected String[] getServletMappings() {
return new String[] { "/api/*" };
}
}
The config class.
package configs;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.sql.DataSource;
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"model"})
#PropertySource("classpath:/application.properties")
public class Config {
#Bean
public JdbcTemplate getTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}
#Bean
public DataSource dataSource(Environment env) {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl(env.getProperty("hsql.url"));
var populator = new ResourceDatabasePopulator(
new ClassPathResource("schema.sql"),
new ClassPathResource("data.sql")
);
DatabasePopulatorUtils.execute(populator, ds);
return ds;
}
}
Then the controller.
package controllers;
import model.Order;
import model.OrderDAO;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
public class OrderController {
private OrderDAO orderdao;
public OrderController(OrderDAO orderDAO) {
this.orderdao = orderDAO;
}
#PostMapping("orders")
#ResponseStatus(HttpStatus.CREATED)
public Order saveOrder(#RequestBody Order order) {
return orderdao.addOrder(order);
}
#GetMapping("orders/{id}")
public Order getOrderById(#PathVariable Long id) {
return orderdao.getOrderById(id);
}
#GetMapping("orders")
public List<Order> getOrders() {
return orderdao.getAllOrders();
}
#DeleteMapping("orders/{id}")
public void deleteOrderById(#PathVariable Long id) {
orderdao.deleteOrderById(id);
}
}
Everything seems fine, I can't find the issue.
Since the OrderController is in the controllers package, I forgot to add the package in the configs componentScan parameters.
Your controller registers the endpoints at /orders/*, but in getServletMappings you specify the /api/*. You should add /api prefix to your controller, like this
#RestController
#RequestMapping("api")
public class OrderController {
...
We are using spring mvc with java configuration.
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.TimeZone;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesView;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
#Configuration
#EnableWebMvc
#EnableAspectJAutoProxy
#ComponentScan(basePackages = {"com.anonymous"})
public class WebConfig extends WebMvcConfigurerAdapter {
#Value("${webCachePeriod}")
private int cachePeriod;
#Value("${maxUploadSize}")
private long maxUploadSize;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/app/**").addResourceLocations("/app/");
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/").setCachePeriod(cachePeriod);
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod);
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
}
private MappingJackson2HttpMessageConverter converter() {
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false)
.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false)
.setTimeZone(TimeZone.getTimeZone("GMT"))
.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"));
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(mapper);
return converter;
}
#Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions(new String[] {"/WEB-INF/views/tiles.xml"});
tilesConfigurer.setCheckRefresh(true);
return tilesConfigurer;
}
#Bean
public UrlBasedViewResolver viewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(TilesView.class);
return viewResolver;
}
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(maxUploadSize);
return multipartResolver;
}
}
While deploying the war we are getting the exception.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tilesConfigurer' defined in class path resource [com/expedia/risk/cm/config/WebConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: No URL for ServletContext resource [/WEB-INF/views/tiles.xml]
Please see what is the problem with this thing, I tried but this looks okay to me.
I tried to implement my own HandlerMapping. It's registering well, but when i try to handle request it gives me 404, without even catching it by handleRequest(). That's how it looks like:
MyHandlerMapping:
package com.szymon.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.BeansException;
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
public class MyHandlerMapping extends AbstractUrlHandlerMapping {
private List<String> mappings = new ArrayList<String>();
#Override
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
mappings.add("/test");
mappings.add("/home");
mappings.add("/index");
registerHandlers();
}
protected void registerHandlers() {
mappings.stream().forEach(elem -> {
registerHandler(elem, "myController");
});
}
}
My Controller:
package com.szymon.config;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class MyController implements Controller {
#Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView modelAndView = new ModelAndView("bar");
modelAndView.addObject("test", "test");
System.out.println("test");
System.out.println("test");
System.out.println("test");
return modelAndView;
}
}
And because I'm using Spring Boot :
package com.szymon;
import com.szymon.config.MyController;
import com.szymon.config.MyHandlerMapping;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public MyController myController() {
return new MyController();
}
#Bean
public MyHandlerMapping myHandlerMapping() {
return new MyHandlerMapping();
}
}
Any idea why it doesnt work?
The solution was to invoke setOrder method of AbstractHandlerMapping in bean definition.
I have been trying to add spring validators to a spring-data-rest project.
I followed along and setup the "getting started" application via this link: http://spring.io/guides/gs/accessing-data-rest/
...and now I am trying to add a custom PeopleValidator by following the documents here:
http://docs.spring.io/spring-data/rest/docs/2.1.0.RELEASE/reference/html/validation-chapter.html
My custom PeopleValidator looks like
package hello;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public class PeopleValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return true;
}
#Override
public void validate(Object target, Errors errors) {
errors.reject("DIE");
}
}
...and my Application.java class now looks like this
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
#Configuration
#EnableJpaRepositories
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public PeopleValidator beforeCreatePeopleValidator() {
return new PeopleValidator();
}
}
I would expect that POSTing to the http://localhost:8080/people URL would result in an error of some kind since the PeopleValidator is rejecting everything. However, no error is thrown, and the validator is never called.
I have also tried manually setting up the validator as shown in section 5.1 of the spring-data-rest documentation.
What am I missing?
So it appears that the before/after "save" events only fire on PUT and PATCH. When POSTing, the before/after "create" events fire.
I tried it the manual way again using the configureValidatingRepositoryEventListener override and it worked. I'm not sure what I'm doing differently at work than here at home. I'll have to look tomorrow.
I sure would love to hear if others have suggestions on why it wouldn't work.
For the record, here is what the new Application.java class looks like.
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
#Configuration
#EnableJpaRepositories
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
public class Application extends RepositoryRestMvcConfiguration {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
validatingListener.addValidator("beforeCreate", new PeopleValidator());
}
}
Looks like the feature is currently not implemented (2.3.0), unluckily there are no constants for the event names otherwise the solution below would not be that fragile.
The Configuration adds all properly named Validator beans to ValidatingRepositoryEventListener using the right event.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
import org.springframework.validation.Validator;
#Configuration
public class ValidatorRegistrar implements InitializingBean {
private static final List<String> EVENTS;
static {
List<String> events = new ArrayList<String>();
events.add("beforeCreate");
events.add("afterCreate");
events.add("beforeSave");
events.add("afterSave");
events.add("beforeLinkSave");
events.add("afterLinkSave");
events.add("beforeDelete");
events.add("afterDelete");
EVENTS = Collections.unmodifiableList(events);
}
#Autowired
ListableBeanFactory beanFactory;
#Autowired
ValidatingRepositoryEventListener validatingRepositoryEventListener;
#Override
public void afterPropertiesSet() throws Exception {
Map<String, Validator> validators = beanFactory.getBeansOfType(Validator.class);
for (Map.Entry<String, Validator> entry : validators.entrySet()) {
EVENTS.stream().filter(p -> entry.getKey().startsWith(p)).findFirst()
.ifPresent(p -> validatingRepositoryEventListener.addValidator(p, entry.getValue()));
}
}
}
A bit of a stab in the dark - I've not used spring-data-rest. However, after having a read of the tutorial you're following, I think the problem is that you need a PersonValidator not a PeopleValidator. Rename everything accordingly:
PersonValidator
package hello;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public class PersonValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return true;
}
#Override
public void validate(Object target, Errors errors) {
errors.reject("DIE");
}
}
Application
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
#Configuration
#EnableJpaRepositories
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public PersonValidator beforeCreatePersonValidator() {
return new PersonValidator();
}
}
Another way of doing it is to use annotated handlers as specified here
http://docs.spring.io/spring-data/rest/docs/2.1.0.RELEASE/reference/html/events-chapter.html#d5e443
Here is an example of how to use annotated handlers:
import gr.bytecode.restapp.model.Agent;
import org.springframework.data.rest.core.annotation.HandleBeforeCreate;
import org.springframework.data.rest.core.annotation.HandleBeforeSave;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.stereotype.Component;
#Component
#RepositoryEventHandler(Agent.class)
public class AgentEventHandler {
public static final String NEW_NAME = "**modified**";
#HandleBeforeCreate
public void handleBeforeCreates(Agent agent) {
agent.setName(NEW_NAME);
}
#HandleBeforeSave
public void handleBeforeSave(Agent agent) {
agent.setName(NEW_NAME + "..update");
}
}
Example is from github edited for brevity.
I'm new working with Spring MVC and I have some problems to add multi language to my application.
I dont' use xml configuration. I have a #Configuration class
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.springexamples.basic.controller")
public class BasicServletConfig extends BaseConfig {
#Bean
ViewResolver viewResolver() {
return getViewResolver("views/basic/", ".jsp");
}
#Bean
MessageSource messageSource() {
return getMessageSource("/messages/messages");
}
#Bean
LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}
#Bean
LocaleResolver localeResolver() {
return new SessionLocaleResolver();
}
#Bean
HandlerMapping handlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setInterceptors(new HandlerInterceptor[] { localeChangeInterceptor() });
return mapping;
}
}
When I test de application always I see the default language (spanish). I send the request with the parameter 'lang=en' or 'lang=EN' but I still see it in default language.
¿Anyone knows the solution?.
Thanks,
I'm not sure how HandlerMapping declared this way will play with #EnableWebMvc. A more idiomatic way to configure interceptors with #EnableWebMvc is to use WebMvcConfigurer:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.springexamples.basic.controller")
public class BasicServletConfig extends BaseConfig implements WebMvcConfigurer {
...
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
...
}