Using Property files in Spring 4 MVC - spring-mvc

I have some properties that I have put in a property file config.properties in the dir resources/config.config.properties.
I have the servlet.xml spring config file in the resources dir. It has this line
<util:properties id="nodeProperty"
location="classpath:config/config.properties" />
<context:property-placeholder properties-ref="nodeProperty"/>
In my controller I want to use the property from the file. Hence I have this line
#Autowired
#Value ("${paths.root}")
private String rootPath;
later in a web method I am saying
String rootPath = rootPath;
For this line I am getting the variable not initialized error for compiling.
If anyone has any solutions to this problem please let me know..

Solved the issue using a q posted on stackoverflow. Added the following line in the servlet.xml
<util:properties id="someid" location="classpath:config/config.properties"/>
and then in my controller
private #Value("#{someid['paths.root']}") String rootPath;
Removed the #autowired and it worked!

Related

Error resolving template with Spring Boot using Thymeleaf packaged in a .jar

I have a Spring Boot application using Thymeleaf as template resolver, which works fine when debugging from NetBeans, but gives me this error running its .jar:
Error resolving template "/theme/property", template might not exist or might not be accessible by any of the configured Template Resolvers
The app is set to auto-configurer with the annotation #SpringBootApplication, at an extension of SpringBootServletInitializer. I haven't set any contextPath into the properties file. I'm using Thymeleaf 2.1.6 and Spring 4 version. The jar is generated with Maven.
Doing some research I've come out that in some controllers I was passing a double slash, which I've solved but most pages still not working.
This controller works:
#GetMapping("/{idweb}")
String frontEndHome(#PathVariable("idweb")Integer idweb, Model model){
...
return "theme/home";
With the return statement set as return "/theme/home"; doesn't work. I guess, because the template resolver is recieving a double slash (//).
This other controller raises the error:
#GetMapping("/{idweb}/property")
String frontEndProperty(#PathVariable("idweb") Integer idweb, #RequestParam(value = "idproperty", required = false) Integer idproperty, Model model) throws Exception {
...
return "theme/property";
The index controller works fine as well:
#GetMapping("/")
public String index(Model model){
...
return "index";
}
That's my application starter class:
#SpringBootApplication
public class RentalWebsApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(RentalWebsApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(RentalWebsApplication.class, args);
}
}
For Thymeleaf I haven't set any configuration, although I've tested the app setting this into the application.properties file, with the same result:
spring.thymeleaf.prefix=classpath:/templates/
All html files are set into:
src/main/resources/templates
The html files from the examples are in:
src/main/resources/templates/index.html
src/main/resources/templates/theme/home.html
src/main/resources/templates/theme/property.html
There are some other questions dealing with the same issue, but none has a solution that works for me. Any help, would be much appreciated.
Update
Deploying the jar into Pivotal Web Services, the whole website works fine, but not deploying it with Boxfuse, Heroku or running the jar locally. Therefore, I guess the origin of the problem is some wrong configuration, that Pivotal system detects and corrects.*
*
PWS isn't correcting a configuration problem. It unpacks your jar file before running the application which stops the double slash from causing a problem. – Andy Wilkinson
At the end the solution was related to the double slashes, that the classpath:/templates/ gets if we set a return statement with a slash at the beginning like:
return "/theme/property"
Instead of:
return "theme/property"
In my case, the problem was not at the controller, but in the html with the Thymeleaf references of fragments, like in this example:
<footer th:replace="/index::footer"></footer>
Instead of:
<footer th:replace="index::footer"></footer>
What I don't understand is why the IDE's (NetBeans and STS), where not raising the error.
use
return new ModelAndView("member2",map);
instead of
return new ModelAndView("/member2",map);
Remove spring.thymeleaf.prefix=classpath:/templates/ from your application.properties.

StrictHttpFirewall in spring security 4.2 vs spring MVC #MatrixVariable

Having upgraded to spring security 4.2.4 I discovered that StrictHttpFirewall is now the default.
Unfortunately it doesn't play well with spring MVC #MatrixVariable since ";" are not allowed anymore.
How to get around that?
Example:
#GetMapping(path = "/{param}")
public void example(#PathVariable String param,
#MatrixVariable Map<String, String> matrix) {
//...
}
This could be called like this:
mockMvc.perform(get("/someparam;key=value"))
And the matrix map would be populated.
Now spring security blocks it.
org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL contained a potentially malicious String ";"
at org.springframework.security.web.firewall.StrictHttpFirewall.rejectedBlacklistedUrls(StrictHttpFirewall.java:140)
I could use a custom HttpFirewall that would allow semicolons.
Is there a way to use #MatrixVariable without using forbidden characters?
BTW: the javadoc is incorrect https://docs.spring.io/autorepo/docs/spring-security/4.2.x/apidocs/index.html?org/springframework/security/web/firewall/StrictHttpFirewall.html
Since:
5.0.1
I guess it was backported?
You can dilute the default spring security firewall using your custom defined instance of StrictHttpFirewall (at your own risk)
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
firewall.setAllowSemicolon(true);
return firewall;
}
And then use this custom firewall bean in WebSecurity (Spring boot does not need this change)
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
// #formatter:off
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
...
}
That shall work with Spring Security 4.2.4+, but of-course that brings some risks!
As mentioned by Крис in a comment if you prefer to use a XML approach, you can add the following part to your securityContext.xml (or whatever your spring-security related xml-config is called):
<bean id="allowSemicolonHttpFirewall"
class="org.springframework.security.web.firewall.StrictHttpFirewall">
<property name="allowSemicolon" value="true"/>
</bean>
<security:http-firewall ref="allowSemicolonHttpFirewall"/>
The <bean> part defines a new StrictHttpFirewall bean with the id allowSemicolonHttpFirewall which is then set as default http-firewall in the <security> tag by referencing the id.
I used combination of following two
https://stackoverflow.com/a/48636757/6780127
https://stackoverflow.com/a/30539991/6780127
First one resolved the
The request was rejected because the URL contained a potentially malicious String ";"
Second one Resolved the
Spring MVC Missing matrix variable
As I am using Spring Security with Spring Web I had to do both And the issue is now Resolved.
I found using #MatrixVariable Following Pattern is useful. First in Url {num} has to be mentioned to use it as #MatrixVariable
#RequestMapping(method = RequestMethod.GET,value = "/test{num}")
#ResponseBody
public ResponseEntity<String> getDetail(#MatrixVariable String num){
return new ResponseEntity<>("test"+num, HttpStatus.OK);
}

asp.net dynamically add connection string in web.config

I have web application and windows application in same solution. I want to dynamically add connection string in web.config file. The connection string information give from windows application. How do i do this please help me.
My window app having:
WebForm1 wf = new WebForm1();
wf.add();
And my wep app having:
public void add()
{
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConnectionStringsSection sec = (ConnectionStringsSection)config.GetSection("connectionStrings");
sec.ConnectionStrings["DBCS"].ConnectionString = "Data Source=GKS_004-PC;Database=hello1;User ID=123;Password=123";
config.Save();
}
I believe you address your problem in a way that may exist a different approach to solve your issue, however in order to do what you want you have two options. First you can read the file using the IO namespace and then parse it like XML using LINQ nodes and second you can use the Configuration class (System.Configuration and System.Web.Configuration namespaces).
//get the configuration file
Configuration config = WebConfigurationManager.OpenWebConfiguration("..."); //path to config
//get Configuration section
ConfigurationSection section = config.GetSection("...");
config.AppSettings.Settings.Add(Key, Value);
config.AppSettings.Settings.Remove(Key);
or this way, instead of using directly Configuration class
AppSettingsSection appsettings = (AppSettingsSection) config.GetSection("...");
appsettings.Settings.Add(key, Value);

Spring Web Flow Conversion Service in JavaConfig

I've started working on a web application in Spring Weblow. The idea is to write as much as possible in Java, rather than XML. So I started off with a JavaConfig file for both the MVC configuration and the Web Flow configuration. But I ran into a problem when needing converters for entering and submitting a form with Spring Web Flow.
I did a lot of research on ConversionService and Converters. I found plenty examples of implementing a custom ConversionService and custom Converters, but I found no examples to to add the ConversionService to the Web Flow configuration in JavaConfig (configuration was always XML).
I did try to reproduce the XML config in Java, which nearly worked. In a form page, a list of POJOs (Employee) was represented as a dropdownlist. The input was List<Employee> and the converter (subclass of StringToObject) worked to represent each Employee as a String. But when submitting the form, I got the error that no converter was found for String to Employee. So basically, the custom converter was found and used when rendering the page, but when submitting the form, the same converter could not be found for the reverse process.
I eventually got it fixed by rolling the JavaConfig back to XML config and adding a custom Formatter to the ConversionService of the MVC config. But I'd like to make this work in JavaConfig if it is at all possible.
I believe the problem is that a ConversionService bean (org.springframework.core.convert package) needs to be added to the MVC config, because this bean needs to be set as a delegate ConversionService in the ConversionService bean to be added to the Web Flow Config (the latter from the org.springframework.binding.convert package). But I don't know how to add this core ConversionService in JavaConfig like in the mvc:annotation-driven tag in the code below.
It all boils down to needing the JavaConfig version of the following code:
<mvc:annotation-driven conversion-service="typeConversionService" ... />
<bean id="typeConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<list>
<bean class="some.package.holidays.formatter.EmployeeFormatter">
<constructor-arg ref="employeeService"/>
</bean>
<bean class="org.springframework.format.datetime.DateFormatter">
<constructor-arg value="dd/MM/yyyy"/>
</bean>
</list>
</property>
</bean>
If anyone would know about JavaConfig for Spring Webflow, especially about adding a ConversionService, please let me know, it would be a great help.
I had the same thing to do in a project and this is how I did it. I know it might be late for you, but maybe somebody else needs the answer to this:
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
private MvcConfig webMvcConfig;
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setValidator(this.webMvcConfig.validator())
.setConversionService(conversionService())
.setDevelopmentMode(true)
.build();
}
#Bean
DefaultConversionService conversionService() {
return new DefaultConversionService(conversionServiceFactoryBean().getObject());
}
#Bean
FormattingConversionServiceFactoryBean conversionServiceFactoryBean() {
FormattingConversionServiceFactoryBean fcs = new FormattingConversionServiceFactoryBean();
Set<Formatter> fmts = new HashSet<>();
fmts.add(this.webMvcConfig.dateFormatter());
fmts.add(this.webMvcConfig.employeeFormatter());
fcs.setFormatters(fmts);
return fcs;
} }
I upvoted the accepted answer but would also like to add this. I kept getting the below error.
'conversionService': Requested bean is currently in creation: Is there an unresolvable circular reference?
To fix this, remove conversionService bean like this. (note the setConversionService difference).
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setValidator(localValidatorFactoryBean)
.setConversionService(new DefaultConversionService(conversionServiceFactoryBean().getObject()))
.setDevelopmentMode(true)
.build();
}
#Bean
FormattingConversionServiceFactoryBean conversionServiceFactoryBean() {
FormattingConversionServiceFactoryBean fcs = new FormattingConversionServiceFactoryBean();
Set<Formatter> fmts = new HashSet<>();
fmts.add(this.webMvcConfig.dateFormatter());
fmts.add(this.webMvcConfig.employeeFormatter());
fcs.setFormatters(fmts);
return fcs;
}

creating and access properties file in spring mvc

read this article on SO, and had some clarifying questions.
I put my config.properties under src/main/resources
In spring-servlet.xml config file
I added the following:
<context:property-placeholder location="classpath:config.properties"/>
In my business layer, I am trying to access it via
#Value("${upload.file.path}")
private String uploadFilePath;
Eclipse shows error:
The attribute value is undefined for the annotation type Value
Can i not access the property in the business layer or are property files only read in the controller?
UPDATE::
src/main/java/com.companyname.controllers/homecontroller.java
public String home(Locale locale, Model model) {
MyServiceObject myObj = new MyServiceObject();
System.out.println("Property from my service object: = " + myObj.PropertyValue());
if(myObj.PerformService())
{
///
}
}
src/main/java/com.companyname.services/MyService.java
public class MyServiceObject {
#Value("${db.server.ip}")
private String _dbServerIP;
public String PropertyValue() {
return _dbServerIPaseURL;
}
}
Another site where I found the explanation
Please check that you import Value from org.springframework.beans.factory.annotation package:
import org.springframework.beans.factory.annotation.Value;
also the property placeholder must be declared in the respective context configuration file, in case of controller it's likely Spring dispatcher servlet configuration file.
update You are confusing property-placeholder that post processes bean values, that contain dollar symbol ${<property name>} with Spring expression language container extension that process values containing a hash symbol #{<Spring expression language expression>}, in the link you have shown the latter approach is used.
regarding the instantiation of MyServiceObject myObj
If you want the object to be managed by Spring you should delegate its creation to the container:
if MyServiceObject is a stateless service then it's a singleton with the singleton bean scope, you should register it in your application context, for example with the following xml configuration:
<bean class="my.package.MyServiceObject"/>
and inject it to your controller:
private MyServiceObject myServiceObject;
#Autowired
public void setMyServiceObject(MyServiceObject myServiceObject){
this.myServiceObject = myServiceObject;
}
if many instances of MyServiceObject are required, you can declare it as a bean with some other (non-singleton) bean scope (prototype, or request, for example).
However, as there's only one instance of the controller, you can't merely let the Spring container to autowire MyServiceObject instance to the controller field, because there will be only one field and many instances of MyServiceObject class. You can read about the different approaches(for the different bean scopes) for resolving this issue in the respective section of the documentation.
Here is a method that allows us to fetch whatever values are needed from a property file. This can be in Java code (Controller class) or in a JSP.
Create a property file WEB-INF/classes/messageSource.properties It will be in the classpath and accessible in both controllers and JSTL.
Like any property file, this one consists of a key and a value
For example:
hello=Hello JSTL, Hello Contoller
For the Controllers
Locate the xml file that you use to define your Spring beans. In my case it is named servlet-context.xml. You may need to determine that by looking in your web.xml in cases where you are using the servlet contextConfigLocation property.
Add a new Spring bean definition with the id="messageSource". This bean will be loaded at runtime by Spring with the property file key value pairs. Create the bean with the following properties:
bean id="messageSource"
class = org.springframework.context.support.ReloadableResourceBundleMessageSource
property name="basename" value="WEB-INF/classes/messageSource
In the bean definition file for the controller class (testController) add the messageSource as a property. This will inject the messageSource bean into the controller.
bean id="testController" class="com.app.springhr.TestController"
beans:property name="messageSource" ref="messageSource"
In the controller JAVA class, add the messageSource Spring Bean field and its getters and setters. Note the field type is ReloadableResourceBundleMessageSource.
private org.springframework.context.support.ReloadableResourceBundleMessageSource messageSource;
public org.springframework.context.support.ReloadableResourceBundleMessageSource getMessageSource() {
return messageSource;
}
public void setMessageSource(
org.springframework.context.support.ReloadableResourceBundleMessageSource messageSource) {
this.messageSource = messageSource;
}
In your controller code, you can now fetch any known property value from the bundle.
String propValue = getMessageSource().getMessage("hello", objArray, null);
Using JSTL
Since the property file messageSource.properties is in the classpath, JSTL will be able to find it and fetch the value for the given key.
Add the import of the fmt taglib
taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"
Use the fmt:tag in the JSP to fetch a value from the property file.
Sorry about the pseudo syntax, this editor doesn't seem to render any XML.
fmt:bundle basename="messageSource"
fmt:message key="hello"
Hope this helps others

Resources