The only relevant question I could I find here is this one.
Unfortunately unlike the above mentioned question I am not using file names as a path variable. What I am sending in a string which may or may not have '.'. As a result I do not want to use a strategy mentioned in the solution for the above question.
This is my WebConfigAdapter:
#Configuration
public class WebConfigAdapter extends WebMvcConfigurerAdapter {
#Autowired
HandlerExceptionResolver exceptionHandler;
/**
* Disable content negotiation for path extensions.
*
* #param configurer
*/
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
/**
* Set the exception handler.
*
* #param exceptionResolvers
*/
#Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
super.configureHandlerExceptionResolvers(exceptionResolvers);
exceptionResolvers.add(exceptionHandler);
}
/**
* Serve static resources.
*
* #param registry
*/
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
I import WebConfigAdapater in my WebConfig (a java file) like so:
#Configuration
#EnableWebMvc
#Import(value = { WebConfigAdapter.class, WebConfigSupport.class })
public class WebConfig {
#Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
public HandlerExceptionResolver exceptionHandler() {
return new ExceptionHandler();
}
}
And in my application context xml:
<bean class="com.quova.platform.portal.config.WebConfig"/>
I still cant figure out when I use Spring mock mvc in my unit tests, why the below controller receives the string input it strips off the characters after the last period in the string including the period.
#RequestMapping(value = "/{ip}", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public Info lookup(#PathVariable("ip") String ip) throws Exception {
Here's how I am calling the above endpoint in my unit test:
String ip = "4.3.2";
mockMvc.perform(get("/secure/resources/iplookup/{ip}", ip)).andExpect(status().isBadRequest());
So now what the controller sees is "4.3". Also this is my first question on stack overflow, so do let me know if i am missing some needed information or can explain better my question in a better way! Thanks for the help!
#RequestMapping(value = "/{ip:.*}", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public Info lookup(#PathVariable("ip") String ip) throws Exception {
This works
Related
I have the below security configuration in my Spring-Boot app at the moment. This is the standard stuff I've found online to allow all CORs requests (there are a lot of other configurations online that I've also tried).
These work fine for GET requests, however PATCH and DELETE requests are still being blocked due to CORs policy. Has anyone experienced this before?
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
}
}
Right, so I fixed this with the below configuration, however there is a caveat to it: I'd tried this before, however I the first import suggestion for CorsFilter was not the correct one (org.apache.catalina.filters.CorsFilter). This time, I imported the second instead (org.springframework.web.filter.CorsFilter) and this now works.
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
}
#Configuration
public class CorsConfig {
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:3000");
config.addAllowedHeader("*");
config.addAllowedMethod("POST");
config.addAllowedMethod("GET");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
}
You can add the global support for CORS by creating the following bean
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
You can use addAllowedMethod to add additional method in default allowed methods(GET, HEAD, POST)
CorsConfiguration corsConfig = new CorsConfiguration().applyPermitDefaultValues();
corsConfig.addAllowedMethod(HttpMethod.DELETE);
corsConfig.addAllowedMethod(HttpMethod.PUT);
http.cors().configurationSource(request -> corsConfig);
On more recent versions of Spring Security if you look at the CorsRegistration allowedMethods() you'll see
/**
* Set the HTTP methods to allow, e.g. {#code "GET"}, {#code "POST"}, etc.
* <p>The special value {#code "*"} allows all methods.
* <p>By default "simple" methods {#code GET}, {#code HEAD}, and {#code POST}
* are allowed.
*/
public CorsRegistration allowedMethods(String... methods) {
this.config.setAllowedMethods(Arrays.asList(methods));
return this;
}
That by default only GET, HEAD, and POST are allowed.
Adding the additional methods or all ... which might look something like this
#Profile(value = { "LOCAL" })
#Configuration
public class CorsConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedMethods("*") <-- This is the ticket
.allowedOrigins("*")
;
}
};
}
}
Should do the trick
I use spring mvc with spring configuration (without xml). And it seems like IDEA doesn't go to controller code. Maybe somewhere path is incorrect so #RequestMapping doesn't work. But i can't understand where exactly.
Here is my Controller
#Controller
public class MainController {
#RequestMapping(value = "/" , method = RequestMethod.GET)
public String home() {
return "index";
}
#RequestMapping(value = "welcome", method = RequestMethod.GET)
public String welcome(Model m){
m.addAttribute("name","lol kkeke");
return "index2";
}
}
WebMvcConfig
#Configuration
#ComponentScan("com.chat")
#EnableWebMvc
public class WebMVCConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/scripts/**").addResourceLocations("/scripts/");
registry.addResourceHandler("/styles/**").addResourceLocations("/styles/");
registry.addResourceHandler("/images/**").addResourceLocations("/images/");
registry.addResourceHandler("/fonts/**").addResourceLocations("/fonts/");
registry.addResourceHandler("/pages/**").addResourceLocations("/views/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("/index.jsp");
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
}
So.. I solved a problem. It was in Controller - path. My Idea automatically change path from com.chat.controller to c.c.controller. So i rebuild project structure to com.chat.controller.Controller.class; and com.chat.config.Configuration.class.
Also, i found the next article about similar trouble. May be it will help somebody! How do I map Spring MVC controller to a uri with and without trailing slash?
I'm using Spring Boot 1.3.5 with Rest Controllers and everything is working fine.
I am also using Spring's validation sample techniques from the official documentation (JSR-303 Bean Validation API and Spring's validator interface, i tried both and faced the same problem) and the validations are working, but I am not able to configure custom messages.
I have configured a messages.properties file, and I can access the messages on this file just fine. However this validation seems not to be capable of reading or accessing my messages source (messages.properties) configured automatically via spring boot.
I can access the messages directly from the messages source object injected in controller via #Autowired (there's a comment in the code). However, the binding result of the Spring's validator interface or the JSR-303 Bean Validation seems to not be capable of accessing the messages.properties loaded in MessageSource. The result I have is that my errors have codes but don't have default messages.
Here is my Application class:
#SpringBootApplication
#ImportResource({ "classpath:security/cas-context.xml", "classpath:security/cas-integration.xml",
"classpath:security/security.xml" })
#EnableAutoConfiguration(exclude = VelocityAutoConfiguration.class) // http://stackoverflow.com/questions/32067759/spring-boot-starter-cache-velocity-is-missing
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ServletRegistrationBean cxfServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/services/*");
}
#Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public Nfse nfseService() {
return new NfseImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), nfseService());
endpoint.publish("/nfseSOAP");
return endpoint;
}
}
Here is my Bean:
public class Protocolo {
private Long id;
#NotNull
#Min(1)
#Max(1)
private String protocolo;
private StatusProtocoloEnum status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProtocolo() {
return protocolo;
}
public void setProtocolo(String protocolo) {
this.protocolo = protocolo;
}
public StatusProtocoloEnum getStatus() {
return status;
}
public void setStatus(StatusProtocoloEnum status) {
this.status = status;
}
}
Here is My rest controller:
#RestController
public class ProtocoloController {
#Autowired
private MessageSource messageSource;
#Autowired
private ProtocoloDAO protocoloDAO;
#RequestMapping(value = "/prot", method = RequestMethod.POST)
public void testar(#Valid #RequestBody Protocolo p) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println(auth.getAuthorities());
System.out.println(messageSource.getMessage("protocolo.tamanho", null, null));
// IN THIS PART I'M ABLE TO PRINT THE MESSAGE IF VALIDATION IS DISABLED
System.out.println(p.getProtocolo());
}
}
So, this code works fine and the method is not called since i'm calling the method with a invalid Protocolo. However, my angularJS client receives the response with the errors codes populated but with all the default messages empty since the validation is not seeing my loaded messages.properties.
Is there a way to make my Spring validation Interfaces or JSR-303 validation incorporate the loaded message.properties (messagesource) in spring boot ? How can i correct this ? If it's necessary i can paste my code sample of Spring Validation interfaces also.
Thank's a lot,
Tarcísio.
TEST CODE:
#RestController
public class ProtocoloController {
#Autowired
private MessageSource messageSource;
#Autowired
private ProtocoloDAO protocoloDAO;
#RequestMapping(value = "/prot", method = RequestMethod.POST)
public void testar(#Valid #RequestBody Protocolo p, BindingResult bindingResult) {
System.out.println(messageSource.getMessage("Min.protocolo.protocolo", null, null));
if (bindingResult.hasErrors()) {
System.out.println(bindingResult.getFieldError().getDefaultMessage());
System.out.println(bindingResult.getFieldError().getCode());
}
System.out.println(p.getProtocolo());
}
}
Edit:
Known Bug in Spring Boot 1.5.3 see https://github.com/spring-projects/spring-boot/issues/8979
In Spring Boot since 1.5.3 you need to do this
#Configuration
public class ValidationMessageConfig {
#Bean
public LocalValidatorFactoryBean mvcValidator(MessageSource messageSource) {
LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean();
factory.setValidationMessageSource(messageSource);
return factory;
}
}
and then it will work.
With version 1.5.2 and before you can extend WebMVcConfigurerAdapter
#Configuration
public class ProfileMvcConfig extends WebMvcConfigurerAdapter {
private MessageSource messageSource;
#Autowired
public ProfileMvcConfig(MessageSource messageSource) {
this.messageSource = messageSource;
}
/**
* This method is overridden due to use the {#link MessageSource message source} in bean validation.
*
* #return A Validator using the {#link MessageSource message source} in bean validation.
*/
#Override
public Validator getValidator() {
LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean();
factory.setValidationMessageSource(messageSource);
return factory;
}
}
also see the documentation
In Spring Boot applicaton MessageSource is configured with a MessageSourceAutoConfiguration and you don't need to autowire it. For jsr303, create proper key-value pair in the messages.properties file. For "protocolo" field, you should have following values in property file.
NotNull.protocolo.protocolo=Field cannot be left blank
Min.protocolo.protocolo=Minimum value must be {1}
You can also check messages from property file like below in your code.
public void testar(#Valid #RequestBody Protocolo p,BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
System.out.println(bindingResult.getFieldError().getDefaultMessage());
}
}
you should have following values in property file:
Min.protocolo.protocolo=Minimum value must be {1}
then in the controller you obtain the message by calling function getMessage from messageSource object
Test code:
#RequestMapping(value = "/prot", method = RequestMethod.POST)
public void testar(#Valid #RequestBody Protocolo p, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
bindingResult.getFieldErrors().forEach(fieldError ->
System.out.println(messageSource.getMessage(fieldError, Locale.getDefault()))
);
}
System.out.println(p.getProtocolo());
}
I solved this in custom message in Spring validation read the last part of my answer.
Check this example as well.
I used a custom validator with custom annotation. I needed to change code in my custom validator.
public class PersonValidator implements ConstraintValidator {
#Override
public boolean isValid(final Person person, final ConstraintValidatorContext context) {
if (somethingIsInvalid()) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("Something is invalid.").addConstraintViolation();
return false;
}
return true;
}
}
I have a RESTful Spring application with two #Configuration classes
and my swagger methods are listed twice.
I have a swagger config
#Configuration
#EnableSwagger // Loads the spring beans required by the framework
public class SwaggerConfig {
private SpringSwaggerConfig springSwaggerConfig;
/**
* Required to autowire SpringSwaggerConfig
* #param springSwaggerConfig spring swagger config
*/
#Autowired
public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) {
this.springSwaggerConfig = springSwaggerConfig;
}
/**
* Every SwaggerSpringMvcPlugin bean is picked up by the swagger-mvc
* framework - allowing for multiple swagger groups i.e. same code base
* multiple swagger resource listings.
* #return SwaggerSpringMvcPlugin
*/
#Bean
public SwaggerSpringMvcPlugin customImplementation() {
return new SwaggerSpringMvcPlugin(this.springSwaggerConfig)
.apiInfo(apiInfo())
.includePatterns(".*myPattern.*")
.useDefaultResponseMessages(false)
.apiVersion("1.1.0");
}
private ApiInfo apiInfo() {
ApiInfo apiInfo = new ApiInfo("my Service REST API",
null /*"REST API for my service."*/, null /*"My Apps API terms of service"*/,
null /*"myemail#mycompany.de"*/, null /*"My Apps API Licence Type"*/,
null /*"My Apps API License URL"*/);
return apiInfo;
}
}
And, to solve this issue: Get Request fails for .com email addresses because Spring interpretes it as a extensions, I have a second config:
#Configuration
#EnableWebMvc
public class RestCommonsMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}
But now all of my swagger methods are listed twice. If I remove the #EnableWebMvc annotation, they are all listed just once again, but the config does not do anymore what it is expected to do (fix above mentioned bug).
What can I do now?
edit
I tried to extend from WebMvcConfigurationSupport directly, but the problem does not disappear.
#Configuration
public class MyConfiguration extends WebMvcConfigurationSupport {
//#EnableWebMvc
//public class RestCommonsMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}
I'm struggling with trying to return a static web page from a spring MVC controller.
I followed this tutorial: http://www.tutorialspoint.com/spring/spring_static_pages_example.htm and yet it still isn't working.
This is how I defined the configuration (used configuration class):
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan({ "com.my.web.api"})
#ImportResource("classpath:db-context.xml")
public class ApiServletConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setPrefix("/resources/");
internalResourceViewResolver.setSuffix("*.html");
return internalResourceViewResolver;
}
}
The controller method:
#RequestMapping(value = "/{id}/view", method = RequestMethod.GET, produces = "text/html")
#ResponseBody
public String getPostByIdHtml( #PathVariable String id) throws IOException {
return "/resources/Post.html";
}
Under the webapp folder there's a folder named "resources" and under which there's a file "Post.html". What else should I do in order to get this page returned as HTML instead of getting the string "resources/Post.html"?
Thanks for the help.
Please remove the annotation #ResponseBody. Your browser should be redirected to the desired page once the annotation is removed.
This annotation indicates that the value returned by a method in your controller should be bound to the web response body. In your case, you do not need that: you need Spring to render page /resources/Post.html, so no need for this annotation.