I've a spring boot web application that can serve files from a static file location in server.
I've specified the location in properties file and using it to configure the ResourceHandlerRegistry.
#SpringBootApplication
public class MyWebApplication {
#Value("${targetdirectory}")
private String targetDirectory;
#Bean
WebMvcConfigurer configurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
targetDirectory = StringUtils.appendIfMissing(targetDirectory, "/", "/");
targetDirectory = StringUtils.prependIfMissing(targetDirectory, "file:/", "file:/");
registry.addResourceHandler("/resourcetarget/**").addResourceLocations(targetDirectory);
}
};
}
public static void main(String[] args) {
SpringApplication.run(MyWebApplication.class, args);
}
}
Everything works as expected. Now I have to dynamically set the resource location based on user input.
After the application is loaded, the user triggers an HTTP post request where he can specify the directory by which can be used as the resource location.
So after that any requests to the /resourcetarget/** should be mapped to the directory which the user specified. Following is the controller I have.
#RestController
#RequestMapping(value = "api/locations", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class MyController {
#PostMapping
public ResponseEntity<Object> handleLocationSet(#RequestBody LocationDTO locationDto) {
String newFileLocation = locationDto.getLocation();
// How do I update the ResourceHandlerRegistry mapping for /resourcetarget/**
// with the new location received here?
return ResponseEntity.ok();
}
}
How can I update the mapping for this dynamic location for a static resource url. Please help
Related
I have this resource handler, and I am able to call the static web page located in different location , but I am trying to call from controller class I am not able to get the page
#Configuration
public class Static_ResourceHandler implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/system/files/**").addResourceLocations("file:/home/niteshb/Documents/data");
}
}
This is what I am calling
http://localhost:8080/system/files/test.html
but how to call it from controller , I was trying something like this but its not working
This is my controller class call ..
#GetMapping("/")
public String getfile() {
return "test.html";
}
Create a Get mapping for /system/files/, for which you had created the resource handler,
and return the file in the newly created method.
#GetMapping("/system/files/")
public String getStaticfile() {
return "/system/files/test.html";
}
Hope that should work.
I'm trying to allow cors from the same server, with port 3000.
As I don't know where my server is going to be deployed, I tried to access the server name as string than concat it with my desired port.
So here is my approach :
#SpringBootApplication
public class TestApplication {
#Autowired
private HttpServletRequest request;
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
System.out.println(request.getServerName());
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins(request.getServerName()+":3000");
}
};
}
}
I think these are the highlights of my error message :
Error creating bean with name 'corsConfigurer'
org.springframework.beans.BeanInstantiationException: Failed to instantiate
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread?
A good practice is to specify the allowed origins in the application.properties file and read it in your WebConfig.class. That allows you to easy add your production address later.
application.yml
web:
allowedOrigins:
- "http://localhost:4200"
- "some other"
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private final String[] allowedOrigins;
public WebMvcConfig(#Value("${web.allowedOrigins:}") String[] allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //
.allowedMethods("*") //
.allowCredentials(true) //
.allowedOrigins(allowedOrigins);
}
}
just use localhost, no need to access server name
Controller needs uses .htm extensions for all handlers, including JSON REST endpoints. How should I test for REST endpoints?
Problem:
I cannot disable suffix interpretation and I am getting 406 "Could not find acceptable representation"
Tried attempts:
I reviewed posts on stackoverflow related to 406, but could not find relevant one to the case where 'htm' suffix is used in tests. When you remove '.htm' suffix from both Controller and Test - the test is passing.
Here is controller with /changePassword.htm endpoint:
#Controller
public class MainController {
public static class ResultBean {
private final String result;
public String getResult() {
return result;
}
public ResultBean(String result) {
this.result = result;
}
}
#RequestMapping(value="/changePassword.htm", method= RequestMethod.POST, produces = { "application/json" })
public #ResponseBody ResultBean changePassword (
#RequestParam("username") String username, #RequestParam("password") String password) {
return new ResultBean("OK");
}
}
And here is the test with configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { HomeControllerTest.Config.class })
public class HomeControllerTest {
#InjectMocks
private MainController controller = new MainController();
private MockMvc mvc;
#Configuration
#EnableWebMvc
public static class Config extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false)
.favorParameter(true)
.parameterName("mediaType")
.ignoreUnknownPathExtensions(true)
.ignoreAcceptHeader(false)
.useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON);
}
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(controller)
.build();
}
#Test
public void shouldPassChangePasswordBean() throws Exception {
mvc.perform(post("/changePassword.htm")
.accept("*/*")
.param("username", "example")
.param("password", "abcdef")
)
.andExpect(status().isOk()); // Test produces 406 instead of 200
}
}
Any idea?
On newer version of Spring (4+ I think), mime type is determined from suffix first.
So If you use a .htm suffix, Spring will default to produce HTML even if you don't want to.
One way to bypass this is to use a filter that rewrite URL. For instance tuckey URL rewriter filter
With this, you can set some rules like:
/my/page/that/return/json.htm is rewriten to /my/page/that/return/json so that Spring can produce data according to the Accept header.
with Spring 5, try changing your URL of your web service to .json! that is the right fix. great details here http://stick2code.blogspot.com/2014/03/solved-orgspringframeworkwebhttpmediaty.html
I recently migrated to Spring boot. I used Spring MVC before. When I go to a site after the application starts, this throws 404 page not found. The controller handles the request, but for some reason does not find the jsp page.
My Application.java:
package com.myapp.webapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication(scanBasePackages = "com.myapp")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.properties
# Spring MVC configuration
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.datasource.url=jdbc:mysql://us-cdbr-iron-east-05.cleardb.net/heroku_4663e71bc0d567a?reconnect=true
spring.datasource.username=bb1a6d3ce29ada
spring.datasource.password=******
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/socialnet?autoReconnect=true&useSSL=false
#spring.datasource.username=root
#spring.datasource.password=123
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
debug=true
And controller for example
package com.myapp.webapp;
//imports
#Controller
#SessionAttributes({"accountInSession", "base64Photo"})
public class MainController {
private static final Logger logger = LoggerFactory.getLogger(MainController.class);
#Autowired
private AccountService accountService;
#Autowired
private AuthenticationTrustResolver authenticationTrustResolver;
#RequestMapping(value = {"/login", "/"})
public ModelAndView loginPage(#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout,
#RequestParam(value = "noLogin", required = false) String noLogin) {
ModelAndView modelAndView = new ModelAndView("/login");
if (error != null) {
modelAndView.addObject("error", "Incorrect mail and/or password");
//modelAndView.setViewName("login");
}
if (logout != null) {
modelAndView.addObject("msg", "You've been logged out successfully!");
//modelAndView.setViewName("login");
}
if (noLogin != null) {
modelAndView.addObject("error", "Please log in to view this page");
}
if (!isCurrentAuthenticationAnonymous()) {
//modelAndView.setViewName("login");
modelAndView.setViewName("redirect:/account");
return modelAndView;
}
return modelAndView;
}
#RequestMapping("/test")
public String test() {
return "redirect:/registration";
}
}
For example if I go to http://localhost:8080/test controller redirected me to http://localhost:8080/registration
I used a multi module maven project with models: common(for models), dao, service and webapp.
So controllers located in
java/com/myapp/webapp/controllers
Jsp pages located in
src/main/webapp/WEB-INF/jsp
And path to files:
java/com/myapp/Application.java
src/main/resources/application.properties
And structure of wepapp module
You need to provide your implementation of view resolver using WebMvcConfigurer.
WebMvcConfigurer has replaced the old, deprecated WebMvcConfigurerAdapter.
#EnableWebMvc
#Configuration
#ComponentScan
public class CustomWebConfig implements WebMvcConfigurer {
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
}
You need to provide prefix(/WEB-INF/jsp/) and suffix(.jsp) explicitly as registry.jsp()method takes default prefix as /WEB-INF/ and suffix as .jsp.
Refer Spring Framework: ViewResolverRegistry class
I have solve this problem. I move all jsp files from src/main/wepapp/WEB-INF/jsp/
to src/main/resources/META-INF/resources/WEB-INF/jsp/. I have no idea why it not works before, but now it works
Spring Boot with Spring Data Rest - how to use a custom error handler.
Created an error controller I tried to skip the default error handler by using following code.
Why it is not working!
#Configuration
#EnableJpaRepositories
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration(exclude = { BasicErrorController.class })
#EnableMetrics
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
.....................
.....................
and error controller as below
#Component
#RestController
#RequestMapping(value = "/error")
public class CustomErrorController extends BasicErrorController {
public CustomErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes);
// TODO Auto-generated constructor stub
}
private static final String PATH = "/error";
#RequestMapping(value = PATH)
public String error() {
return "Error handling";
}
#Override
public String getErrorPath() {
return PATH;
}
}
I haven't used this kind of solution, but, it seems that your request mapping is not right.
The request mapping of CustomErrorController is '/error', and in
#RequestMapping(value = PATH)
public String error() {
return "Error handling";
}
There is a another '/error' in request mapping path. Then the url for this error handler is '/error/error'.
You have #RequestMapping("/error") annotation on your controller and second #RequestMapping("/error") on your method. This results in /error/error mapping, not the /error mapping as you specified in getErrorPath() method and maybe in your configuration (application.properties, server.path.error).