一直用groovy写脚本,groovy兼容java语法,又在jvm上运行,对于java开发入门门槛很低,
公司有个新项目就采用了springboot+ jdk1.7(升级到1.8),springboot1.5(后升级到2.0) + groovy2.5 + mongodb,
springboot升级到2其中遇到很多问题,由于中间的错误没有记录,这里就不描述了,我把已经调试通过的配置粘贴到下面,希望对有需要的人有些帮助。
,除了对泛型继承支持不好,其它比java代码简洁
groovy 有几个要注意的地方
- 方法上返回泛型,groovy转换不了,类继承泛型的返回转换不了
- BeanUtils复制时,要注意去掉metaClass,父类默认有这个属性
- 取spring上下文,只有这种方式可以取到,如下,其它继承接口或者其它方式都不行
@Autowired
ApplicationContext context - maven打包时需要增加插件gmavenplus-plugin
- GString不要做为Map的key
Groovy优点:
- 可以省很多代码,让代码更简洁
例如 : def map = [:]
def list = []
def hello(name, password){} - 可以用def定义通用类型,不需要转换, , def name
- 字符串支持多行, 有可变字符串GString,和普通字符串
- 普通字符串用单引号,或者三单引号定义
def name = ‘World’ 或者 def name = ‘’‘World’’’
可变字符串用 双引号或者三双引号定义
def greeting = “Hello ${name}!” 或者
def greeting = “”“Hello ${name}!”""
demo部分代码
POM.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!--<version>1.5.13.RELEASE</version>-->
<version>2.1.1.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<!-- case -->
<dependency>
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>1.5.0-GA</version>
</dependency>
<!-- case -->
<!--<dependency>-->
<!--<groupId>org.springframework.security</groupId>-->
<!--<artifactId>spring-security-web</artifactId>-->
<!--</dependency>-->
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- spring boot -->
<!-- web -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!--web -->
<!-- swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.2.2</version>
</dependency>
<!-- swagger2 -->
<!-- apache -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.2.1</version>
</dependency>
<!-- apache -->
<!-- else -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.15</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.9.2</version>
<!--<version>3.7.5</version> -->
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
<!--<version>1.1.0.FINAL</version>-->
</dependency>
<!-- else -->
<!-- Spring Boot test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot test -->
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--<version>1.5.9.RELEASE</version>-->
<version>2.1.1.RELEASE</version>
<configuration>
<executable>true</executable>
<mainClass>com.winit.dis.m.Application</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- <version>2.3.2</version> -->
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
<verbose>true</verbose>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.6.1</version>
<configuration>
<sourceEncoding>UTF-8</sourceEncoding>
<sources>
<source>
<directory>${project.basedir}/src/main/java</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</source>
</sources>
<testSources>
<testSource>
<directory>${project.basedir}/src/test/java</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</testSource>
</testSources>
<!-- 用maven编译时需要加encoding:mvn -Dfile.encoding=UTF-8 compile -->
</configuration>
<executions>
<execution>
<goals>
<goal>addSources</goal>
<goal>addTestSources</goal>
<goal>compile</goal>
<goal>compileTests</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
application.properties 配置:
server.port= 8081
spring.async.corePoolSize= 10
spring.async.maxPoolSize= 200
spring.async.queueCapacity= 10
spring.async.threadNamePrefix= dis-Executor-
####################### mongodb ###########################
mongo.replicaSet=172.16.3.115:27017
mongo.dbName=dis
mongo.connectionsPerHost=200
mongo.threadsAllowedToBlockForConnectionMultiplier=100
mongo.connectTimeout=10000
mongo.maxWaitTime=15000
mongo.autoConnectRetry=true
mongo.socketKeepAlive=false
mongo.socketTimeout=15000
mongo.slaveOk=true
mongo.writeNumber=1
mongo.writeTimeout=0
mongo.writeFsync=true
mongo.username=winit_dis
mongo.password=winit2015
#上面是升级前的配置,留着没有删除
spring.data.mongodb.uri: mongodb://${mongo.username}:${mongo.password}@${mongo.replicaSet}/${mongo.dbName}
##############redis################
redisson.master-name=redis-master-cn
redisson.sentinel-addresses=127.0.0.1:10000,127.0.0.1:10000
redisson.slaveConnectionPoolSize=10
redisson.masterConnectionPoolSize=10
redisson.timeout=3000
redisson.password=
## CAS 配置
cas.serverLoginUrl=http://172.16.3.207:180/cas/login
cas.serverUrlPrefix=http://172.16.3.207:180/cas
#cas.clientHostUrl=http://172.16.3.115:8081/index
cas.clientHostUrl=http://10.99.6.209:8081/index
cas.signOutFilters=/logout
cas.ignorePattern=/api/*
spring.thymeleaf.content-type= text/html
#启用MVC Thymeleaf视图分辨率
spring.thymeleaf.enabled= true
#模板编码
spring.thymeleaf.mode= LEGACYHTML5
# 在构建URL时预先查看名称的前缀
spring.thymeleaf.prefix= classpath:/templates/
# 构建URL时附加查看名称的后缀.
spring.thymeleaf.suffix= .html
logging.config: classpath:logback.xml
Application.groovy:
@SpringBootApplication(scanBasePackages = "com.winit.dis.m")
@EnableAspectJAutoProxy(proxyTargetClass = true)
@EnableAsync
@EnableTransactionManagement(proxyTargetClass = true)
@EnableScheduling
@Configuration
class Application{
static void main(String[] args) {
SpringApplication.run(Application.class, args)
}
}
CasClientConfiguration.groovy:
@Configuration
@EnableConfigurationProperties(CasClientConfigurationProperties.class)
class CasClientConfiguration {
@Autowired
CasClientConfigurationProperties configProps
/**
* 配置登出过滤器
* @return
*/
@Bean
FilterRegistrationBean filterSingleRegistration() {
final FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new SingleSignOutFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("casServerUrlPrefix", configProps.getServerUrlPrefix());
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(1);
return registration;
}
/**
* 配置过滤验证器 这里用的是Cas30ProxyReceivingTicketValidationFilter
* @return
*/
@Bean
FilterRegistrationBean filterValidationRegistration() {
final FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new Cas20ProxyReceivingTicketValidationFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("casServerUrlPrefix", configProps.getServerUrlPrefix());
initParameters.put("serverName", configProps.getClientHostUrl());
initParameters.put("useSession", "true");
//initParameters.put("redirectAfterValidation", "true");
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(2);
return registration;
}
/**
* 配置授权过滤器
* @return
*/
@Bean
FilterRegistrationBean filterAuthenticationRegistration() {
final FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new AuthenticationFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("casServerLoginUrl", configProps.getServerLoginUrl());
initParameters.put("serverName", configProps.getClientHostUrl());
if (configProps.getIgnorePattern() != null && !"".equals(configProps.getIgnorePattern())) {
initParameters.put("ignorePattern", configProps.getIgnorePattern());
}
//自定义UrlPatternMatcherStrategy 验证规则
if (configProps.getIgnoreUrlPatternType() != null && !"".equals(configProps.getIgnoreUrlPatternType())) {
initParameters.put("ignoreUrlPatternType", configProps.getIgnoreUrlPatternType());
}
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(3);
return registration;
}
/**
* request wraper过滤器
* @return
*/
@Bean
FilterRegistrationBean filterWrapperRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean()
registration.setFilter(new HttpServletRequestWrapperFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
// 设定加载的顺序
registration.setOrder(4);
return registration;
}
/**
* 添加登出监听器
* @return
*/
@Bean
ServletListenerRegistrationBean<EventListener> singleSignOutListenerRegistration() {
ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<EventListener>()
registrationBean.setListener(new SingleSignOutHttpSessionListener());
registrationBean.setOrder(1);
return registrationBean;
}
/**
* 该过滤器使得可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
* 比如AssertionHolder.getAssertion().getPrincipal().getName()。
* 这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息
*/
@Bean
public FilterRegistrationBean assertionThreadLocalFilter() {
FilterRegistrationBean filterRegistration = new FilterRegistrationBean()
filterRegistration.setFilter(new AssertionThreadLocalFilter())
filterRegistration.addUrlPatterns("/*")
filterRegistration.setOrder(7)
return filterRegistration
}
@Bean
UserFilter registerUserFilter(){
return new UserFilter();
}
/**
* 配置用户过滤器,过滤相关用户权限
* @return
*/
@Bean
FilterRegistrationBean userFilter(){
FilterRegistrationBean filterRegistration = new FilterRegistrationBean()
filterRegistration.setFilter(registerUserFilter());
filterRegistration.addUrlPatterns("/*")
filterRegistration.setOrder(8)
return filterRegistration
}
}
CasClientConfigurationProperties.groovy
@ConfigurationProperties(
prefix = "cas"
)
class CasClientConfigurationProperties {
String serverUrlPrefix;
String serverLoginUrl;
String clientHostUrl;
String ignorePattern
String ignoreUrlPatternType
}
RedissonProperties.groovy
@ConfigurationProperties(prefix = "redisson")
class RedissonProperties {
int timeout = 3000
String address
String password
int connectionPoolSize = 64
int connectionMinimumIdleSize = 10
int slaveConnectionPoolSize = 250
int masterConnectionPoolSize = 250
String[] sentinelAddresses
String masterName
}
RedissonConfig.groovy
@Configuration
@ConditionalOnClass(Config.class)
@EnableConfigurationProperties(RedissonProperties.class)
class RedissonConfig {
@Autowired
RedissonProperties redssionProperties;
/**
* 哨兵模式自动装配
* @return
*/
@Bean
RedissonClient redissonSentinel() {
Config config = new Config();
SentinelServersConfig serverConfig = config.useSentinelServers().addSentinelAddress(redssionProperties.getSentinelAddresses())
.setMasterName(redssionProperties.getMasterName())
.setTimeout(redssionProperties.getTimeout())
.setMasterConnectionPoolSize(redssionProperties.getMasterConnectionPoolSize())
.setSlaveConnectionPoolSize(redssionProperties.getSlaveConnectionPoolSize());
if (StringUtils.isNotBlank(redssionProperties.getPassword())) {
serverConfig.setPassword(redssionProperties.getPassword());
}
return Redisson.create(config);
}
}
项目结构截图: