I am working on a java web application, manag开发者_JAVA技巧ed by maven2. From time to time, we did some changes, and want to do new releases, of course with new version number. In the homepage (jsp), there is text like
<b>version:</b> 2.3.3...
Is it possible, every time I do a new release, I only change the <version/>
in pom.xml, and version number in jsp can be automatically filled by this maven ${project.version}?
I tried maven profile, however it doesn't seem to work.
any ideas?
Thank you.
You can use project filtering to process the JSP as it is copied to the target location. If the JSP is specified with ${project.version}
, and the containing folder is specified as a filter location the value should be substituted into the JSP as it is packaged.
For example, adding this to your POM enables filtering for src/main/resources:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
Update: for war packaging, you may need to configure the war plugin to do its filtering. See the Filtering
section of the war-plugin's documentation for more details and examples.
Essentially the process is the same, but it is defined below the war plugin, so you'd have something like this:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0</version>
<configuration>
<webResources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
It's maybe stupid but I'd use a .properties
file like in this example instead of filtering directly the JSP.
Use the maven-replacer-plugin
Include the plugin in your pom.xml like this:
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>(version)</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<ignoreMissingFile>true</ignoreMissingFile>
<file>target/someapp/jsp/helloWorld.jsp</file>
<outputFile>
target/someapp/jsp/helloWorld-updated.jsp
</outputFile>
<regex>false</regex>
<token>$BUILD_NUMBER$</token>
<value>${buildNumber}</value>
</configuration>
</plugin>
Now anywhere in the specified file that has the token$BUILD_NUMBER$
the token will get replaced.
It make a while this post have been created, but I hope it would help. It will get properties generated from Maven :
<%@ page import="java.util.*"%>
<%
java.io.InputStream inputStream = getServletContext().getResourceAsStream("/META-INF/maven/com.filhetallard.fam.ged/famdox/pom.properties");
Properties mavenProperties= new Properties();
mavenProperties.load(inputStream );
String version = (String) mavenProperties.get("version");
String name = (String) mavenProperties.get("artifactId");
%><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<title>Application <%= name %> v<%= version %></title>
Unfortunately, there is some drawbacks :
- you had to explicitely write groupId and artifactId in your code
- if you deploy your web-app directly from target/ to your server, it won't find the file because this one is in maven-archiver directory, not in META-INF, before packaging.
Regards.
I wanted to do this very same thing but I was not satisfied with any of the existing solutions, including using the Maven filtering approach, which is ok, but I am trying to move away from modifying existing code files during the build process so I ruled that approach out, although it is a reasonable approach.
The way I get my Maven project version into my JSP file is based on a similar approach to the one from here except that I don't create a Version.java file, instead I just have Maven write the version out to a properties file, such as "version.properties" like this:
version.properties:
app.version = 0.1
and have Maven put it on the classpath, for instance, in src/main/resources like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<goals>
<goal>run</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<!-- Idea from link: http://stackoverflow.com/questions/2469922/generate-a-version-java-file-in-maven -->
<target>
<property name="resources.dir" value="${project.build.sourceDirectory}/../resources" />
<property name="version.filename" value="version.properties" />
<property name="buildtime" value="${maven.build.timestamp}" />
<echo message="Writing project version string to ${resources.dir}/${version.filename} ..." />
<echo file="${resources.dir}/${version.filename}" message="app.version = ${project.version}${line.separator}" />
</target>
</configuration>
</execution>
</executions>
</plugin>
Also, if you are using Spring Framework 3.x+ then you can add the following configuration to load properties in version.properties if it exists, otherwise just show "v0.0" or whatever:
@Configuration
@EnableWebMvc
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class WebHomeConfig extends WebMvcConfigurerAdapter implements
ApplicationContextAware {
private ApplicationContext _appContext;
/*
* (non-Javadoc)
*
* @see
* org.springframework.context.ApplicationContextAware#setApplicationContext
* (org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
_appContext = appContext;
}
@Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.getAttributesMap().put("appVersion", appVersion);
return resolver;
}
/**
* Since we don't have any controller logic, simpler to just define
* controller for page using View Controller. Note: had to extend
* WebMvcConfigurerAdapter to get this functionality
*
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
/**
* The application version.
*/
@Value("${app.version:0.0}")
protected String appVersion;
@Bean
public static PropertySourcesPlaceholderConfigurer configurer() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setIgnoreResourceNotFound(true);
configurer.setLocations(new Resource[] {
new ClassPathResource("version.properties")});
return configurer;
}
}
And finally, in your /WEB-INF/views/home.jsp you can have something like:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Service Status</title>
</head>
<body>
<h1>Service API</h1>
<p>The service is up and running! (v${appVersion})</p>
</body>
</html>
And this would of course render as:
The service is up and running! (v0.1)
NOTE: If you don't use the JavaConfig classes to configure Spring Framework then you can do the same thing with Spring XML configuration.
I use this plugin,
http://code.google.com/p/maven-substitute-plugin/
You can do something like this in Java,
public final static String projectVersion = "@PROJECT_VERSION@";
and it's trivial to pass this value to JSP.
Parent pom.xml:
<properties>
<!-- in my case injected by jenkins build job -->
<build.version>dev</build.version>
<build.branch>local</build.branch>
<build.revision />
</properties>
Resource filtering (placeholders are replaced by pom-property values here)
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>conf/version.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
Bean and property placeholder config in webContext.xml:
<context:property-placeholder location="classpath:conf/version.properties"/>
<bean id="buildVersion" class="de.your.package.cfg.BuildVersion">
<property name="buildBranch" value="${build_branch}"/>
<property name="buildVersion" value="${build_version}"/>
<property name="buildRevision" value="${build_revision}"/>
</bean>
Your bean looks like this then
@Component
public class BuildVersion {
private String buildBranch;
private String buildVersion;
private String buildRevision;
public String getBuildRevision() {
return buildRevision;
}
public void setBuildRevision(String buildRevision) {
this.buildRevision = buildRevision;
}
public String getBuildVersion() {
return buildVersion;
}
public void setBuildVersion(String buildVersion) {
this.buildVersion = buildVersion;
}
public String getBuildBranch() {
return buildBranch;
}
public void setBuildBranch(String buildBranch) {
this.buildBranch = buildBranch;
}
}
And here comes your JSP snippet:
<%@ page language="java"
import="java.util.*,
org.springframework.context.ApplicationContext,
org.springframework.web.context.support.WebApplicationContextUtils,
de.smava.kredithai.cfg.BuildVersion" %>
<%
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(pageContext.getServletContext());
BuildVersion buildVersion = (BuildVersion) applicationContext.getBean("buildVersion");
String branch = (String) buildVersion.getBuildBranch();
String version = (String) buildVersion.getBuildVersion();
String revision = (String) buildVersion.getBuildRevision();
if (request.getParameter("branch") != null){
out.println(branch);
} else if (request.getParameter("version") != null){
out.println(version);
} else if (request.getParameter("link") != null){
out.println("<a href=\"http://your_server_url"+branch+"/"+version+"\" >" + branch + " build " + version + "</a>");
} else {
out.println(branch + " build " + version + " rev. " + revision);
}
%>
I would hand the .jsp the value of
String version = getClass().getPackage().getImplementationVersion();
that would look like 1.0.0-SNAPSHOT
for instance.
If you are just getting nulls, you may need to add the classpath to the Manifest of the war
with
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
for the classloader to pick it up.
There are many ways of passing the values (as discussed in these comments). Another approach (which has its own pros and cons) is to add the parameter(s) to the manifest from your POM file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifestEntries>
<Build-Version>${project.version}</Build-Version>
<Build-Date>${buildDateTime}</Build-Date>
<Build-Number>${buildNumber}</Build-Number>
<Build-Revision>${buildRevision}</Build-Revision>
</manifestEntries>
</archive>
</configuration>
</plugin>
and then open and read the manifest to set a singleton bean during configuration or directly import them into the JSP with:
<%
String buildVersion;
String buildDate;
String buildRevision;
String buildNumber;
Attributes attributes;
String version = "";
InputStream in = null;
// Get manifest attributes
try {
Manifest manifest;
in = pageContext.getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF");
manifest = new Manifest(in);
attributes = manifest.getMainAttributes();
} catch (Exception ex) {
attributes = new Attributes();
attributes.put(new Attributes.Name("Build-Version"), "None (Inplace Deployment)");
} finally {
if (in != null) {
in.close();
}
}
buildVersion = attributes.getValue("Build-Version");
buildDate = attributes.getValue("Build-Date");
buildRevision = attributes.getValue("Build-Revision");
buildNumber = attributes.getValue("Build-Number");
%>
One advantage is that this information is also present in the manifest as easy to locate documentation. One disadvantage is the need to open and read the manifest file.
In http://mojo.codehaus.org/jspc/jspc-maven-plugin/usage.html
It states this:
Non-WAR Projects
You can also use this plugin with non-war projects, for instance to validate JSPs. They will be compiled, but not included in your final artifact, and no web.xml file will be generated or modified.
If you want to just validate and compile your JSPs without actually including the generated code in your war project, you can also use set the includeInProject parameter to false.
You can use this in your JSP file (template.jsp in my example)
<head>
<meta name="Historia Social Unica version:${version}" />
Then in your pom.xml of your project you have to activate filtering:
<resources>
<resource>
<includes>
<include>template.jsp</include>
</includes>
<directory>src/main/webapp/jsp/template</directory>
<targetPath>jsp/template/</targetPath>
<filtering>true</filtering>
</resource>
</resources>
</build>
And you obtain your JSP with the variable version replaced.
精彩评论