15 | * Our application always returns the correct time because it uses the
16 | * {@link CurrentTimeDateTimeService} class.
17 | *
18 | *
19 | * When our integration tests are running, we can return a constant time which gives us the possibility
20 | * to assert the creation and modification times saved to the database.
21 | *
22 | *
23 | *
24 | * @author Petri Kainulainen
25 | */
26 | public class AuditingDateTimeProvider implements DateTimeProvider {
27 |
28 | private final DateTimeService dateTimeService;
29 |
30 | public AuditingDateTimeProvider(DateTimeService dateTimeService) {
31 | this.dateTimeService = dateTimeService;
32 | }
33 |
34 | @Override
35 | public Calendar getNow() {
36 | return GregorianCalendar.from(dateTimeService.getCurrentDateAndTime());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/common/ConstantDateTimeService.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.common;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.stereotype.Component;
6 |
7 | import java.time.ZoneId;
8 | import java.time.ZonedDateTime;
9 | import java.time.format.DateTimeFormatter;
10 |
11 | /**
12 | * This class is used in our integration tests and it always returns the same time. This gives us
13 | * the possibility to verify that the correct timestamps are saved to the database.
14 | *
15 | * @author Petri Kainulainen
16 | */
17 | @Component("constantDateTimeService")
18 | public class ConstantDateTimeService implements DateTimeService {
19 |
20 | public static final String CURRENT_DATE_AND_TIME = getConstantDateAndTime();
21 |
22 | private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_ZONED_DATE_TIME;
23 |
24 | private static final Logger LOGGER = LoggerFactory.getLogger(ConstantDateTimeService.class);
25 |
26 | private static String getConstantDateAndTime() {
27 | return "2015-07-19T12:52:28" +
28 | getSystemZoneOffset() +
29 | getSystemZoneId();
30 | }
31 |
32 | private static String getSystemZoneOffset() {
33 | return ZonedDateTime.now().getOffset().toString();
34 | }
35 |
36 | private static String getSystemZoneId() {
37 | return "[" + ZoneId.systemDefault().toString() + "]";
38 | }
39 |
40 | @Override
41 | public ZonedDateTime getCurrentDateAndTime() {
42 | ZonedDateTime constantDateAndTime = ZonedDateTime.from(FORMATTER.parse(CURRENT_DATE_AND_TIME));
43 |
44 | LOGGER.info("Returning constant date and time: {}", constantDateAndTime);
45 |
46 | return constantDateAndTime;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/common/CurrentTimeDateTimeService.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.common;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.stereotype.Component;
6 |
7 | import java.time.ZonedDateTime;
8 |
9 | /**
10 | * This class returns the current time.
11 | *
12 | * @author Petri Kainulainen
13 | */
14 | @Component("dateTimeService")
15 | public class CurrentTimeDateTimeService implements DateTimeService {
16 |
17 | private static final Logger LOGGER = LoggerFactory.getLogger(CurrentTimeDateTimeService.class);
18 |
19 | @Override
20 | public ZonedDateTime getCurrentDateAndTime() {
21 | ZonedDateTime currentDateAndTime = ZonedDateTime.now();
22 |
23 | LOGGER.info("Returning current date and time: {}", currentDateAndTime);
24 |
25 | return currentDateAndTime;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/common/DateTimeService.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.common;
2 |
3 | import java.time.ZonedDateTime;
4 |
5 | /**
6 | * This interface defines the methods used to get the current
7 | * date and time.
8 | *
9 | * @author Petri Kainulainen
10 | */
11 | public interface DateTimeService {
12 |
13 | /**
14 | * Returns the current date and time.
15 | *
16 | * @return
17 | */
18 | ZonedDateTime getCurrentDateAndTime();
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/config/AsyncConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.config;
2 |
3 | import com.springboot.demo.async.ExceptionHandlingAsyncTaskExecutor;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
7 | import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
8 | import org.springframework.boot.bind.RelaxedPropertyResolver;
9 | import org.springframework.context.EnvironmentAware;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 | import org.springframework.context.annotation.Profile;
13 | import org.springframework.core.env.Environment;
14 | import org.springframework.scheduling.annotation.AsyncConfigurer;
15 | import org.springframework.scheduling.annotation.EnableAsync;
16 | import org.springframework.scheduling.annotation.EnableScheduling;
17 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
18 |
19 | import java.util.concurrent.Executor;
20 |
21 | @Configuration
22 | @EnableAsync
23 | @EnableScheduling
24 | @Profile("!" + Constants.SPRING_PROFILE_FAST)
25 | public class AsyncConfiguration implements AsyncConfigurer, EnvironmentAware {
26 |
27 | private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
28 |
29 | private RelaxedPropertyResolver propertyResolver;
30 |
31 | @Override
32 | public void setEnvironment(Environment environment) {
33 | this.propertyResolver = new RelaxedPropertyResolver(environment, "async.");
34 | }
35 |
36 | @Override
37 | @Bean
38 | public Executor getAsyncExecutor() {
39 | log.debug("Creating Async Task Executor");
40 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
41 | executor.setCorePoolSize(propertyResolver.getProperty("corePoolSize", Integer.class, 2));
42 | executor.setMaxPoolSize(propertyResolver.getProperty("maxPoolSize", Integer.class, 50));
43 | executor.setQueueCapacity(propertyResolver.getProperty("queueCapacity", Integer.class, 10000));
44 | executor.setThreadNamePrefix("samplegradle-Executor-");
45 | return new ExceptionHandlingAsyncTaskExecutor(executor);
46 | }
47 |
48 | @Override
49 | public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
50 | return new SimpleAsyncUncaughtExceptionHandler();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/config/Constants.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.config;
2 |
3 | /**
4 | * Application constants.
5 | */
6 | public final class Constants {
7 |
8 | // Spring profile for development, production and "fast", see http://jhipster.github.io/profiles.html
9 | public static final String SPRING_PROFILE_DEVELOPMENT = "dev";
10 | public static final String SPRING_PROFILE_PRODUCTION = "prod";
11 | public static final String SPRING_PROFILE_FAST = "fast";
12 | public static final String SPRING_PROFILE_TEST = "test";
13 |
14 | private Constants() {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/config/DatabaseConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.config;
2 |
3 | import com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module;
4 | import com.springboot.demo.common.AuditingDateTimeProvider;
5 | import com.springboot.demo.common.DateTimeService;
6 | import com.zaxxer.hikari.HikariConfig;
7 | import com.zaxxer.hikari.HikariDataSource;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.boot.bind.RelaxedPropertyResolver;
11 | import org.springframework.context.ApplicationContextException;
12 | import org.springframework.context.EnvironmentAware;
13 | import org.springframework.context.annotation.Bean;
14 | import org.springframework.context.annotation.Configuration;
15 | import org.springframework.core.env.Environment;
16 | import org.springframework.data.auditing.DateTimeProvider;
17 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
18 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
19 | import org.springframework.transaction.annotation.EnableTransactionManagement;
20 | import org.springframework.util.StringUtils;
21 |
22 | import javax.sql.DataSource;
23 | import java.util.Arrays;
24 |
25 | @Configuration
26 | @EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider")
27 | @EnableJpaRepositories("com.springboot.demo.repository")
28 | @EnableTransactionManagement
29 | public class DatabaseConfiguration implements EnvironmentAware {
30 |
31 | private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
32 |
33 | private RelaxedPropertyResolver dataSourcePropertyResolver;
34 |
35 | private Environment env;
36 |
37 | @Override
38 | public void setEnvironment(Environment env) {
39 | this.env = env;
40 | this.dataSourcePropertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");
41 | }
42 |
43 | @Bean(destroyMethod = "close")
44 | public DataSource dataSource() {
45 | log.debug("Configuring Datasource");
46 | if (dataSourcePropertyResolver.getProperty("url") == null
47 | && dataSourcePropertyResolver.getProperty("databaseName") == null) {
48 | log.error("Your database connection pool configuration is incorrect! The application" +
49 | " cannot start. Please check your Spring profile, current profiles are: {}",
50 | Arrays.toString(env.getActiveProfiles()));
51 |
52 | throw new ApplicationContextException("Database connection pool is not configured correctly");
53 | }
54 | HikariConfig config = new HikariConfig();
55 | config.setDataSourceClassName(dataSourcePropertyResolver.getProperty("dataSourceClassName"));
56 | if (StringUtils.isEmpty(dataSourcePropertyResolver.getProperty("url"))) {
57 | config.addDataSourceProperty("databaseName",
58 | dataSourcePropertyResolver.getProperty("databaseName"));
59 | config.addDataSourceProperty("serverName",
60 | dataSourcePropertyResolver.getProperty("serverName"));
61 | } else {
62 | config.addDataSourceProperty("url", dataSourcePropertyResolver.getProperty("url"));
63 | }
64 | config.addDataSourceProperty("user", dataSourcePropertyResolver.getProperty("username"));
65 | config.addDataSourceProperty("password", dataSourcePropertyResolver.getProperty("password"));
66 |
67 | //MySQL optimizations, see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
68 | if ("com.mysql.jdbc.jdbc2.optional.MysqlDataSource".equals(
69 | dataSourcePropertyResolver.getProperty("dataSourceClassName"))) {
70 | config.addDataSourceProperty("cachePrepStmts",
71 | dataSourcePropertyResolver.getProperty("cachePrepStmts", "true"));
72 | config.addDataSourceProperty("prepStmtCacheSize",
73 | dataSourcePropertyResolver.getProperty("prepStmtCacheSize", "250"));
74 | config.addDataSourceProperty("prepStmtCacheSqlLimit", dataSourcePropertyResolver
75 | .getProperty("prepStmtCacheSqlLimit", "2048"));
76 | }
77 | return new HikariDataSource(config);
78 | }
79 |
80 | @Bean
81 | public Hibernate4Module hibernate4Module() {
82 | return new Hibernate4Module();
83 | }
84 |
85 | @Bean
86 | DateTimeProvider dateTimeProvider(DateTimeService dateTimeService) {
87 | return new AuditingDateTimeProvider(dateTimeService);
88 | }
89 |
90 | @Bean
91 | DateTimeProvider constantDateTimeProvider(DateTimeService constantDateTimeService) {
92 | return new AuditingDateTimeProvider(constantDateTimeService);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/config/JacksonConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.fasterxml.jackson.datatype.joda.JodaModule;
5 | import com.springboot.demo.domain.util.CustomDateTimeDeserializer;
6 | import com.springboot.demo.domain.util.CustomDateTimeSerializer;
7 | import com.springboot.demo.domain.util.CustomLocalDateSerializer;
8 | import com.springboot.demo.domain.util.ISO8601LocalDateDeserializer;
9 | import org.joda.time.DateTime;
10 | import org.joda.time.LocalDate;
11 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
12 | import org.springframework.context.annotation.Bean;
13 | import org.springframework.context.annotation.Configuration;
14 | import org.springframework.context.annotation.Primary;
15 |
16 | @Configuration
17 | public class JacksonConfiguration {
18 |
19 | @Bean
20 | public JodaModule jacksonJodaModule() {
21 | JodaModule module = new JodaModule();
22 | module.addSerializer(DateTime.class, new CustomDateTimeSerializer());
23 | module.addDeserializer(DateTime.class, new CustomDateTimeDeserializer());
24 | module.addSerializer(LocalDate.class, new CustomLocalDateSerializer());
25 | module.addDeserializer(LocalDate.class, new ISO8601LocalDateDeserializer());
26 | return module;
27 | }
28 |
29 | @Primary
30 | @Bean
31 | public ObjectMapper jacksonObjectMapper() {
32 | return new ObjectMapper();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/config/MetricsConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.config;
2 |
3 | import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
4 | import org.springframework.boot.actuate.autoconfigure.ExportMetricWriter;
5 | import org.springframework.boot.actuate.metrics.jmx.JmxMetricWriter;
6 | import org.springframework.boot.actuate.metrics.writer.MetricWriter;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.context.annotation.Profile;
10 | import org.springframework.jmx.export.MBeanExporter;
11 |
12 |
13 | @Configuration
14 | @EnableMetrics(proxyTargetClass = true)
15 | @Profile("!" + Constants.SPRING_PROFILE_TEST)
16 |
17 | public class MetricsConfiguration {
18 | @Bean
19 | @ExportMetricWriter
20 | MetricWriter metricWriter(MBeanExporter exporter) {
21 | return new JmxMetricWriter(exporter);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/config/RedisConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.config;
2 |
3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | import org.springframework.data.redis.connection.RedisConnectionFactory;
8 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
9 | import org.springframework.data.redis.core.StringRedisTemplate;
10 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
11 | import redis.clients.jedis.JedisPoolConfig;
12 |
13 |
14 | @Configuration
15 | @EnableAutoConfiguration
16 | public class RedisConfiguration {
17 | @Bean
18 | public RedisConnectionFactory jedisConnectionFactory() {
19 | JedisPoolConfig poolConfig = new JedisPoolConfig();
20 | poolConfig.setMaxTotal(5);
21 | poolConfig.setTestOnBorrow(true);
22 | poolConfig.setTestOnReturn(true);
23 | JedisConnectionFactory ob = new JedisConnectionFactory(poolConfig);
24 | ob.setUsePool(true);
25 | ob.setHostName("localhost");
26 | ob.setPort(6379);
27 | return ob;
28 | }
29 |
30 | @Bean
31 | public StringRedisTemplate stringRedisTemplate(){
32 | StringRedisTemplate template = new StringRedisTemplate(jedisConnectionFactory());
33 | template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
34 | template.setHashKeySerializer(new Jackson2JsonRedisSerializer<>(Object.class));
35 | template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
36 | return new StringRedisTemplate(jedisConnectionFactory());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/config/apidoc/SwaggerConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.config.apidoc;
2 |
3 | import com.springboot.demo.config.Constants;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.boot.bind.RelaxedPropertyResolver;
7 | import org.springframework.context.EnvironmentAware;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.context.annotation.Profile;
11 | import org.springframework.core.env.Environment;
12 | import org.springframework.http.ResponseEntity;
13 | import org.springframework.util.StopWatch;
14 | import springfox.documentation.service.ApiInfo;
15 | import springfox.documentation.spi.DocumentationType;
16 | import springfox.documentation.spring.web.plugins.Docket;
17 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
18 |
19 | import java.util.Date;
20 |
21 | import static springfox.documentation.builders.PathSelectors.regex;
22 |
23 | /**
24 | * Springfox Swagger configuration.
25 | *
26 | * Warning! When having a lot of REST endpoints, Springfox can become a performance issue. In that
27 | * case, you can use a specific Spring profile for this class, so that only front-end developers
28 | * have access to the Swagger view.
29 | */
30 | @Configuration
31 | @EnableSwagger2
32 | @Profile("!" + Constants.SPRING_PROFILE_PRODUCTION)
33 | public class SwaggerConfiguration implements EnvironmentAware {
34 |
35 | private final Logger log = LoggerFactory.getLogger(SwaggerConfiguration.class);
36 |
37 | public static final String DEFAULT_INCLUDE_PATTERN = "/.*";
38 |
39 | private RelaxedPropertyResolver propertyResolver;
40 |
41 | @Override
42 | public void setEnvironment(Environment environment) {
43 | this.propertyResolver = new RelaxedPropertyResolver(environment, "swagger.");
44 | }
45 |
46 | /**
47 | * Swagger Springfox configuration.
48 | */
49 | @Bean
50 | public Docket swaggerSpringfoxDocket() {
51 | log.info("Starting Swagger");
52 | StopWatch watch = new StopWatch();
53 | watch.start();
54 | Docket docket = new Docket(DocumentationType.SWAGGER_2)
55 | .apiInfo(apiInfo())
56 | .genericModelSubstitutes(ResponseEntity.class)
57 | .forCodeGeneration(true)
58 | .genericModelSubstitutes(ResponseEntity.class)
59 | .directModelSubstitute(org.joda.time.LocalDate.class, String.class)
60 | .directModelSubstitute(org.joda.time.LocalDateTime.class, Date.class)
61 | .directModelSubstitute(org.joda.time.DateTime.class, Date.class)
62 | .directModelSubstitute(java.time.LocalDate.class, String.class)
63 | .directModelSubstitute(java.time.ZonedDateTime.class, Date.class)
64 | .directModelSubstitute(java.time.LocalDateTime.class, Date.class)
65 | .select()
66 | .paths(regex(DEFAULT_INCLUDE_PATTERN))
67 | .build();
68 | watch.stop();
69 | log.info("Started Swagger in {} ms", watch.getTotalTimeMillis());
70 | return docket;
71 | }
72 |
73 | /**
74 | * API Info as it appears on the swagger-ui page.
75 | */
76 | private ApiInfo apiInfo() {
77 | return new ApiInfo(
78 | propertyResolver.getProperty("title"),
79 | propertyResolver.getProperty("description"),
80 | propertyResolver.getProperty("version"),
81 | propertyResolver.getProperty("termsOfServiceUrl"),
82 | propertyResolver.getProperty("contact"),
83 | propertyResolver.getProperty("license"),
84 | propertyResolver.getProperty("licenseUrl"));
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/BaseEntity.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.domain;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
7 | import com.springboot.demo.domain.util.CustomDateTimeDeserializer;
8 | import com.springboot.demo.domain.util.CustomDateTimeSerializer;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import org.hibernate.annotations.Type;
12 | import org.joda.time.DateTime;
13 | import org.springframework.data.annotation.CreatedDate;
14 | import org.springframework.data.annotation.LastModifiedDate;
15 | import org.springframework.data.jpa.domain.support.AuditingEntityListener;
16 |
17 | import javax.persistence.*;
18 | import java.io.Serializable;
19 |
20 | @Data
21 | @MappedSuperclass
22 | @EntityListeners(AuditingEntityListener.class)
23 | @EqualsAndHashCode(of = {"id"})
24 | public class BaseEntity implements Serializable {
25 |
26 | @Id
27 | @GeneratedValue(strategy = GenerationType.AUTO)
28 | @Column(name = "id")
29 | @JsonProperty(value = "id")
30 | private Long id;
31 |
32 | @Version
33 | @Column(name = "version")
34 | @JsonIgnore
35 | private Long version;
36 |
37 | @Column(name = "created_at")
38 | @JsonIgnore
39 | @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
40 | @JsonSerialize(using = CustomDateTimeSerializer.class)
41 | @JsonDeserialize(using = CustomDateTimeDeserializer.class)
42 | @CreatedDate
43 | private DateTime createdAt;
44 |
45 | @Column(name = "updated_at")
46 | @JsonIgnore
47 | @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
48 | @JsonSerialize(using = CustomDateTimeSerializer.class)
49 | @JsonDeserialize(using = CustomDateTimeDeserializer.class)
50 | @LastModifiedDate
51 | private DateTime updatedAt;
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/City.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.domain;
18 |
19 | import com.fasterxml.jackson.core.JsonProcessingException;
20 | import com.fasterxml.jackson.databind.ObjectMapper;
21 | import com.springboot.demo.repository.redis.RedisJsonMapper;
22 | import lombok.Data;
23 | import lombok.NoArgsConstructor;
24 |
25 | import javax.persistence.Column;
26 | import javax.persistence.Entity;
27 | import javax.persistence.GeneratedValue;
28 | import javax.persistence.Id;
29 | import java.io.IOException;
30 | import java.io.Serializable;
31 |
32 | @Data
33 | @Entity
34 | @NoArgsConstructor
35 | public class City implements Serializable, RedisJsonMapper{
36 |
37 | private static final long serialVersionUID = 1L;
38 |
39 | @Id
40 | @GeneratedValue
41 | private Long id;
42 |
43 | @Column(nullable = false)
44 | private String name;
45 |
46 | @Column(nullable = false)
47 | private String state;
48 |
49 | @Column(nullable = false)
50 | private String country;
51 |
52 | @Column(nullable = false)
53 | private String map;
54 |
55 | public City(String name, String country) {
56 | super();
57 | this.name = name;
58 | this.country = country;
59 | }
60 |
61 | @Override
62 | public String toJsonString() {
63 | final ObjectMapper jacksonObjectMapper = new ObjectMapper();
64 | try {
65 | return jacksonObjectMapper.writeValueAsString(this);
66 | } catch (JsonProcessingException e) {
67 | e.printStackTrace();
68 | }
69 | return null;
70 | }
71 |
72 | @Override
73 | public City fromJson(String json) {
74 | final ObjectMapper jacksonObjectMapper = new ObjectMapper();
75 | try {
76 | return jacksonObjectMapper.readValue(json, City.class);
77 | } catch (IOException e) {
78 | e.printStackTrace();
79 | }
80 | return null;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/Hotel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.domain;
18 |
19 | import org.hibernate.annotations.NaturalId;
20 |
21 | import javax.persistence.*;
22 | import java.io.Serializable;
23 | import java.util.Set;
24 |
25 | @Entity
26 | public class Hotel implements Serializable {
27 |
28 | private static final long serialVersionUID = 1L;
29 |
30 | @Id
31 | @GeneratedValue
32 | private Long id;
33 |
34 | @ManyToOne(optional = false, cascade = CascadeType.ALL)
35 | @NaturalId
36 | private City city;
37 |
38 | @Column(nullable = false)
39 | @NaturalId
40 | private String name;
41 |
42 | @Column(nullable = false)
43 | private String address;
44 |
45 | @Column(nullable = false)
46 | private String zip;
47 |
48 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
49 | private Set reviews;
50 |
51 | protected Hotel() {
52 | }
53 |
54 | public Hotel(City city, String name) {
55 | this.city = city;
56 | this.name = name;
57 | }
58 |
59 | public City getCity() {
60 | return this.city;
61 | }
62 |
63 | public String getName() {
64 | return this.name;
65 | }
66 |
67 | public String getAddress() {
68 | return this.address;
69 | }
70 |
71 | public String getZip() {
72 | return this.zip;
73 | }
74 |
75 | public Long getId() {
76 | return this.id;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/HotelSummary.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.domain;
18 |
19 | import java.io.Serializable;
20 | import java.math.BigDecimal;
21 | import java.math.MathContext;
22 | import java.math.RoundingMode;
23 |
24 | public class HotelSummary implements Serializable {
25 |
26 | private static final long serialVersionUID = 1L;
27 |
28 | private static final MathContext MATH_CONTEXT = new MathContext(2,
29 | RoundingMode.HALF_UP);
30 |
31 | private final City city;
32 |
33 | private final String name;
34 |
35 | private final Double averageRating;
36 |
37 | private final Integer averageRatingRounded;
38 |
39 | public HotelSummary(City city, String name, Double averageRating) {
40 | this.city = city;
41 | this.name = name;
42 | this.averageRating = averageRating == null ? null : new BigDecimal(averageRating,
43 | MATH_CONTEXT).doubleValue();
44 | this.averageRatingRounded = averageRating == null ? null : (int) Math
45 | .round(averageRating);
46 | }
47 |
48 | public City getCity() {
49 | return this.city;
50 | }
51 |
52 | public String getName() {
53 | return this.name;
54 | }
55 |
56 | public Double getAverageRating() {
57 | return this.averageRating;
58 | }
59 |
60 | public Integer getAverageRatingRounded() {
61 | return this.averageRatingRounded;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/Rating.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.domain;
18 |
19 | public enum Rating {
20 | TERRIBLE, POOR, AVERAGE, GOOD, EXCELLENT,
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/RatingCount.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.domain;
18 |
19 | import com.fasterxml.jackson.core.JsonProcessingException;
20 | import com.fasterxml.jackson.databind.ObjectMapper;
21 | import com.springboot.demo.repository.redis.RedisJsonMapper;
22 | import lombok.Getter;
23 | import lombok.NoArgsConstructor;
24 | import lombok.Setter;
25 |
26 | import java.io.IOException;
27 | import java.io.Serializable;
28 |
29 | @NoArgsConstructor
30 | @Getter
31 | @Setter
32 | public class RatingCount implements Serializable,RedisJsonMapper {
33 |
34 | private static final long serialVersionUID = 1L;
35 |
36 | private Rating rating;
37 |
38 | private long count;
39 |
40 | public RatingCount(Rating rating, long count) {
41 | this.rating = rating;
42 | this.count = count;
43 | }
44 |
45 | @Override
46 | public String toJsonString() {
47 | final ObjectMapper jacksonObjectMapper = new ObjectMapper();
48 | try {
49 | return jacksonObjectMapper.writeValueAsString(this);
50 | } catch (JsonProcessingException e) {
51 | e.printStackTrace();
52 | }
53 | return null;
54 | }
55 |
56 | @Override
57 | public RatingCount fromJson(String json) {
58 | final ObjectMapper jacksonObjectMapper = new ObjectMapper();
59 | try {
60 | return jacksonObjectMapper.readValue(json, RatingCount.class);
61 | } catch (IOException e) {
62 | e.printStackTrace();
63 | }
64 | return null;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/Review.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.domain;
18 |
19 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
20 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
21 | import com.springboot.demo.domain.util.CustomDateTimeDeserializer;
22 | import com.springboot.demo.domain.util.CustomDateTimeSerializer;
23 | import com.springboot.demo.web.rest.dto.ReviewDetailsDto;
24 | import lombok.Data;
25 | import lombok.EqualsAndHashCode;
26 | import org.hibernate.annotations.Type;
27 | import org.hibernate.envers.Audited;
28 | import org.joda.time.DateTime;
29 | import org.springframework.util.Assert;
30 |
31 | import javax.persistence.*;
32 | import javax.validation.constraints.NotNull;
33 |
34 | @Data
35 | @EqualsAndHashCode(callSuper = true)
36 | @Entity
37 | public class Review extends BaseEntity {
38 |
39 | @ManyToOne(optional = false)
40 | private Hotel hotel;
41 |
42 | @Column(nullable = false, name = "idx")
43 | private int index;
44 |
45 | @Column(nullable = false)
46 | @Enumerated(EnumType.ORDINAL)
47 | private Rating rating;
48 |
49 | @NotNull
50 | @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
51 | @JsonSerialize(using = CustomDateTimeSerializer.class)
52 | @JsonDeserialize(using = CustomDateTimeDeserializer.class)
53 | private DateTime checkInDate;
54 |
55 | @Column(nullable = false)
56 | @Enumerated(EnumType.ORDINAL)
57 | @Audited
58 | private TripType tripType;
59 |
60 | @Column(nullable = false)
61 | @Audited
62 | private String title;
63 |
64 | @Column(nullable = false, length = 5000)
65 | @Audited
66 | private String details;
67 |
68 | protected Review() {
69 | }
70 |
71 | public Review(Hotel hotel, int index, ReviewDetailsDto details) {
72 | Assert.notNull(hotel, "Hotel must not be null");
73 | Assert.notNull(details, "Details must not be null");
74 | this.hotel = hotel;
75 | this.index = index;
76 | this.rating = details.getRating();
77 | this.checkInDate = details.getCheckInDate();
78 | this.tripType = details.getTripType();
79 | this.title = details.getTitle();
80 | this.details = details.getDetails();
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/TripType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.domain;
18 |
19 | public enum TripType {
20 | BUSINESS, COUPLES, FAMILY, FRIENDS, SOLO
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/util/CustomDateTimeDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.domain.util;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.core.JsonToken;
5 | import com.fasterxml.jackson.databind.DeserializationContext;
6 | import com.fasterxml.jackson.databind.JsonDeserializer;
7 | import org.joda.time.DateTime;
8 | import org.joda.time.format.ISODateTimeFormat;
9 |
10 | import java.io.IOException;
11 |
12 | /**
13 | * Custom Jackson deserializer for transforming a JSON object to a Joda DateTime object.
14 | */
15 | public class CustomDateTimeDeserializer extends JsonDeserializer {
16 |
17 | @Override
18 | public DateTime deserialize(JsonParser jp, DeserializationContext ctxt)
19 | throws IOException {
20 | JsonToken t = jp.getCurrentToken();
21 | if (t == JsonToken.VALUE_STRING) {
22 | String str = jp.getText().trim();
23 | return ISODateTimeFormat.dateTimeParser().parseDateTime(str);
24 | }
25 | if (t == JsonToken.VALUE_NUMBER_INT) {
26 | return new DateTime(jp.getLongValue());
27 | }
28 | throw ctxt.mappingException(handledType());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/util/CustomDateTimeSerializer.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.domain.util;
2 |
3 | import com.fasterxml.jackson.core.JsonGenerator;
4 | import com.fasterxml.jackson.databind.JsonSerializer;
5 | import com.fasterxml.jackson.databind.SerializerProvider;
6 | import org.joda.time.DateTime;
7 | import org.joda.time.DateTimeZone;
8 | import org.joda.time.format.DateTimeFormat;
9 | import org.joda.time.format.DateTimeFormatter;
10 |
11 | import java.io.IOException;
12 |
13 | /**
14 | * Custom Jackson serializer for transforming a Joda DateTime object to JSON.
15 | */
16 | public class CustomDateTimeSerializer extends JsonSerializer {
17 |
18 | private static DateTimeFormatter formatter = DateTimeFormat
19 | .forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
20 |
21 | @Override
22 | public void serialize(DateTime value, JsonGenerator generator,
23 | SerializerProvider serializerProvider)
24 | throws IOException {
25 | generator.writeString(formatter.print(value.toDateTime(DateTimeZone.UTC)));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/util/CustomLocalDateSerializer.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.domain.util;
2 |
3 | import com.fasterxml.jackson.core.JsonGenerator;
4 | import com.fasterxml.jackson.databind.JsonSerializer;
5 | import com.fasterxml.jackson.databind.SerializerProvider;
6 | import org.joda.time.LocalDate;
7 | import org.joda.time.format.DateTimeFormat;
8 | import org.joda.time.format.DateTimeFormatter;
9 |
10 | import java.io.IOException;
11 |
12 | /**
13 | * Custom Jackson serializer for transforming a Joda LocalDate object to JSON.
14 | */
15 | public class CustomLocalDateSerializer extends JsonSerializer {
16 |
17 | private static DateTimeFormatter formatter = DateTimeFormat
18 | .forPattern("yyyy-MM-dd");
19 |
20 | @Override
21 | public void serialize(LocalDate value, JsonGenerator jgen, SerializerProvider provider)
22 | throws IOException {
23 | jgen.writeString(formatter.print(value));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/util/FixedH2Dialect.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.domain.util;
2 |
3 | import org.hibernate.dialect.H2Dialect;
4 |
5 | import java.sql.Types;
6 |
7 | public class FixedH2Dialect extends H2Dialect {
8 | public FixedH2Dialect() {
9 | super();
10 | registerColumnType(Types.FLOAT, "real");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/domain/util/ISO8601LocalDateDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.domain.util;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.core.JsonToken;
5 | import com.fasterxml.jackson.databind.DeserializationContext;
6 | import com.fasterxml.jackson.databind.JsonDeserializer;
7 | import org.joda.time.LocalDate;
8 | import org.joda.time.format.ISODateTimeFormat;
9 |
10 | import java.io.IOException;
11 |
12 | /**
13 | * Custom Jackson deserializer for transforming a JSON object (using the ISO 8601 date format) to a
14 | * Joda LocalDate object.
15 | */
16 | public class ISO8601LocalDateDeserializer extends JsonDeserializer {
17 |
18 | @Override
19 | public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
20 | throws IOException {
21 | JsonToken t = jp.getCurrentToken();
22 | if (t == JsonToken.VALUE_STRING) {
23 | String str = jp.getText().trim();
24 | return ISODateTimeFormat.dateTimeParser().parseDateTime(str).toLocalDate();
25 | }
26 | if (t == JsonToken.VALUE_NUMBER_INT) {
27 | return new LocalDate(jp.getLongValue());
28 | }
29 | throw ctxt.mappingException(handledType());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/CityRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.repository;
18 |
19 | import com.springboot.demo.domain.City;
20 | import org.springframework.data.domain.Page;
21 | import org.springframework.data.domain.Pageable;
22 | import org.springframework.data.repository.Repository;
23 |
24 | public interface CityRepository extends Repository {
25 |
26 | Page findAll(Pageable pageable);
27 |
28 | Page findByNameContainingAndCountryContainingAllIgnoringCase(String name,
29 | String country, Pageable pageable);
30 |
31 | City findByNameAndCountryAllIgnoringCase(String name, String country);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/HotelRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.repository;
18 |
19 | import com.springboot.demo.domain.City;
20 | import com.springboot.demo.domain.Hotel;
21 | import com.springboot.demo.domain.HotelSummary;
22 | import com.springboot.demo.domain.RatingCount;
23 | import org.springframework.data.domain.Page;
24 | import org.springframework.data.domain.Pageable;
25 | import org.springframework.data.jpa.repository.Query;
26 | import org.springframework.data.repository.Repository;
27 |
28 | import java.util.List;
29 |
30 | public interface HotelRepository extends Repository {
31 |
32 | Hotel findByCityAndName(City city, String name);
33 |
34 | @Query("select new com.springboot.demo.domain.HotelSummary(h.city, h.name, avg(r.rating)) "
35 | + "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
36 | Page findByCity(City city, Pageable pageable);
37 |
38 | @Query("select new com.springboot.demo.domain.RatingCount(r.rating, count(r)) "
39 | + "from com.springboot.demo.domain.Review r where r.hotel = ?1 group by r.rating order by r.rating DESC")
40 | List findRatingCounts(Hotel hotel);
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/ReviewRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.repository;
18 |
19 | import com.springboot.demo.domain.Hotel;
20 | import com.springboot.demo.domain.Review;
21 | import org.springframework.data.domain.Page;
22 | import org.springframework.data.domain.Pageable;
23 | import org.springframework.data.repository.Repository;
24 |
25 | public interface ReviewRepository extends Repository {
26 |
27 | Page findByHotel(Hotel hotel, Pageable pageable);
28 |
29 | Review findByHotelAndIndex(Hotel hotel, int index);
30 |
31 | Review save(Review review);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/redis/HashCache.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.repository.redis;
2 |
3 |
4 | import java.util.concurrent.TimeUnit;
5 |
6 | /**
7 | * Created by himanshu.virmani on 04/06/16.
8 | */
9 | public interface HashCache {
10 | void put(String key, String hashkey, String value);
11 |
12 | void multiPut(String key, V value);
13 |
14 | String get(String key, String hashkey);
15 |
16 | void delete(String key, String hashkey);
17 |
18 | V multiGet(String key, Class clazz);
19 |
20 | void delete(String key);
21 |
22 | void expire(String key, long time, TimeUnit timeUnit);
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/redis/KeyUtils.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.repository.redis;
2 |
3 | /**
4 | * Created by himanshu.virmani on 04/06/16.
5 | */
6 | public class KeyUtils {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/redis/ListCache.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.repository.redis;
2 |
3 | import java.util.Collection;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | /**
7 | * Created by himanshu.virmani on 04/06/16.
8 | */
9 | public interface ListCache {
10 | void push(String key, V value, boolean right);
11 |
12 | void multiAdd(String key, Collection values, boolean right);
13 |
14 | Collection get(String key, Class clazz);
15 |
16 | V pop(String key, boolean right, Class clazz);
17 |
18 | void delete(String key);
19 |
20 | void trim(String key, int start, int end);
21 |
22 | Long size(String key);
23 |
24 | void expire(String key, long time, TimeUnit timeUnit);
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/redis/RedisJsonMapper.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.repository.redis;
2 |
3 | /**
4 | * Created by himanshu.virmani on 05/06/16.
5 | */
6 | public interface RedisJsonMapper {
7 |
8 | String toJsonString();
9 |
10 | T fromJson(String json);
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/redis/SetCache.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.repository.redis;
2 |
3 | import java.util.Set;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | /**
7 | * Created by himanshu.virmani on 04/06/16.
8 | */
9 | public interface SetCache {
10 | void add(String key, V value);
11 |
12 | boolean isMemberOf(String key, V value);
13 |
14 | Set members(String key, Class clazz);
15 |
16 | V pop(String key, Class clazz);
17 |
18 | void delete(String key);
19 |
20 | void expire(String key, long time, TimeUnit timeUnit);
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/redis/ValueCache.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.repository.redis;
2 |
3 | import java.util.Collection;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.concurrent.TimeUnit;
7 |
8 | /**
9 | * Created by himanshu.virmani on 04/06/16.
10 | */
11 | public interface ValueCache {
12 | void put(String key, V value);
13 |
14 | void multiPut(Map keyValues);
15 |
16 | V get(String key, Class clazz);
17 |
18 | List multiGet(Collection keys);
19 |
20 | void delete(String key);
21 |
22 | void expire(String key, long time, TimeUnit timeUnit);
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/repository/redis/impl/HashCacheRedisRepository.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.repository.redis.impl;
2 |
3 | import com.springboot.demo.repository.redis.HashCache;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.data.redis.core.StringRedisTemplate;
6 | import org.springframework.data.redis.hash.DecoratingStringHashMapper;
7 | import org.springframework.data.redis.hash.HashMapper;
8 | import org.springframework.data.redis.hash.JacksonHashMapper;
9 | import org.springframework.stereotype.Component;
10 |
11 | import java.util.HashMap;
12 | import java.util.Map;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | /**
16 | * Created by himanshu.virmani on 04/06/16.
17 | */
18 | @Component("hashCacheRedisRepository")
19 | public class HashCacheRedisRepository implements HashCache {
20 |
21 | @Autowired
22 | private StringRedisTemplate redisTemplate;
23 |
24 | private HashMapper mapper;
25 |
26 | @Override
27 | public void put(String key, String hashkey, String value) {
28 | redisTemplate.opsForHash().put(key, hashkey, value);
29 | }
30 |
31 | @Override
32 | public void multiPut(String key, V obj) {
33 | if (obj == null) return;
34 | if(mapper == null) {
35 | mapper = new DecoratingStringHashMapper<>(new JacksonHashMapper<>((Class) obj.getClass()));
36 | }
37 | redisTemplate.opsForHash().putAll(key, mapper.toHash(obj));
38 | }
39 |
40 | @Override
41 | public String get(String key, String hashkey) {
42 | return (String) redisTemplate.opsForHash().get(key, hashkey);
43 | }
44 |
45 | @Override
46 | public void delete(String key, String hashkey) {
47 | redisTemplate.opsForHash().delete(key, hashkey);
48 | }
49 |
50 | @Override
51 | public V multiGet(String key, Class clazz) {
52 | final Map
16 | */
17 | public class CachingHttpHeadersFilter implements Filter {
18 |
19 | private final Logger log = LoggerFactory.getLogger(CachingHttpHeadersFilter.class);
20 |
21 | // We consider the last modified date is the start up time of the server
22 | private final static long LAST_MODIFIED = System.currentTimeMillis();
23 |
24 | private long CACHE_TIME_TO_LIVE = TimeUnit.DAYS.toMillis(31L);
25 |
26 | private Environment env;
27 |
28 | public CachingHttpHeadersFilter(Environment env) {
29 | this.env = env;
30 | }
31 |
32 | @Override
33 | public void init(FilterConfig filterConfig) throws ServletException {
34 | CACHE_TIME_TO_LIVE =
35 | TimeUnit.DAYS.toMillis(env.getProperty("http.cache.timeToLiveInDays", Long.class, 31L));
36 | }
37 |
38 | @Override
39 | public void destroy() {
40 | // Nothing to destroy
41 | }
42 |
43 | @Override
44 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
45 | throws IOException, ServletException {
46 | HttpServletResponse httpResponse = (HttpServletResponse) response;
47 | HttpServletRequest httpRequest = (HttpServletRequest) request;
48 |
49 | httpResponse.setHeader("Cache-Control", "max-age=" + CACHE_TIME_TO_LIVE + ", public");
50 | httpResponse.setHeader("Pragma", "cache");
51 |
52 | // Setting Expires header, for proxy caching
53 | httpResponse.setDateHeader("Expires", CACHE_TIME_TO_LIVE + System.currentTimeMillis());
54 |
55 | // Setting the Last-Modified header, for browser caching
56 | httpResponse.setDateHeader("Last-Modified", LAST_MODIFIED);
57 |
58 | chain.doFilter(request, response);
59 |
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/propertyeditors/LocaleDateTimeEditor.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.web.propertyeditors;
2 |
3 | import org.joda.time.LocalDateTime;
4 | import org.joda.time.format.DateTimeFormat;
5 | import org.joda.time.format.DateTimeFormatter;
6 | import org.springframework.util.StringUtils;
7 |
8 | import java.beans.PropertyEditorSupport;
9 | import java.util.Date;
10 |
11 | /**
12 | * Custom PropertyEditorSupport to convert from String to
13 | * Date using JodaTime (http://www.joda.org/joda-time/).
14 | */
15 | public class LocaleDateTimeEditor extends PropertyEditorSupport {
16 |
17 | private final DateTimeFormatter formatter;
18 |
19 | private final boolean allowEmpty;
20 |
21 | /**
22 | * Create a new LocaleDateTimeEditor instance, using the given format for
23 | * parsing and rendering.
24 | *
25 | * The "allowEmpty" parameter states if an empty String should be allowed
26 | * for parsing, i.e. get interpreted as null value. Otherwise, an
27 | * IllegalArgumentException gets thrown.
28 | *
29 | * @param dateFormat DateFormat to use for parsing and rendering
30 | * @param allowEmpty if empty strings should be allowed
31 | */
32 | public LocaleDateTimeEditor(String dateFormat, boolean allowEmpty) {
33 | this.formatter = DateTimeFormat.forPattern(dateFormat);
34 | this.allowEmpty = allowEmpty;
35 | }
36 |
37 | /**
38 | * Format the YearMonthDay as String, using the specified format.
39 | *
40 | * @return DateTime formatted string
41 | */
42 | @Override
43 | public String getAsText() {
44 | Date value = (Date) getValue();
45 | return value != null ? new LocalDateTime(value).toString(formatter) : "";
46 | }
47 |
48 | /**
49 | * Parse the value from the given text, using the specified format.
50 | *
51 | * @param text the text to format
52 | * @throws IllegalArgumentException
53 | */
54 | @Override
55 | public void setAsText(String text) throws IllegalArgumentException {
56 | if (allowEmpty && !StringUtils.hasText(text)) {
57 | // Treat empty String as null value.
58 | setValue(null);
59 | } else {
60 | setValue(new LocalDateTime(formatter.parseDateTime(text)));
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/rest/BaseController.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.web.rest;
2 |
3 | /**
4 | * The BaseController class implements common functionality for all Controller
5 | * classes. As of now there is none. But this is used in the Tests for creating
6 | * stand alone controller context
7 | * Controller methods.
8 | *
9 | * @author Matt Warman
10 | */
11 | public class BaseController {
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/rest/CityController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.web.rest;
18 |
19 | import com.springboot.demo.domain.City;
20 | import com.springboot.demo.service.CityService;
21 | import com.springboot.demo.service.criteria.CitySearchCriteria;
22 | import com.springboot.demo.web.rest.errors.CityNotFoundException;
23 | import org.springframework.beans.factory.annotation.Autowired;
24 | import org.springframework.data.domain.Page;
25 | import org.springframework.data.domain.PageRequest;
26 | import org.springframework.http.MediaType;
27 | import org.springframework.transaction.annotation.Transactional;
28 | import org.springframework.web.bind.annotation.*;
29 |
30 | @RestController
31 | @RequestMapping("/city")
32 | public class CityController extends BaseController {
33 |
34 | @Autowired
35 | private CityService cityService;
36 |
37 |
38 | @RequestMapping(value = "/search/{keyword}", method = RequestMethod.GET,
39 | produces = MediaType.APPLICATION_JSON_VALUE)
40 | @ResponseBody
41 | @Transactional(readOnly = true)
42 | public Page search(@PathVariable("keyword") String keyword) {
43 | CitySearchCriteria criteria = new CitySearchCriteria(keyword);
44 | PageRequest pageRequest = new PageRequest(0, 4);
45 | Page result = this.cityService.findCities(criteria, pageRequest);
46 | if (result == null || result.getTotalElements() == 0) {
47 | throw new CityNotFoundException();
48 | }
49 | return result;
50 | }
51 |
52 | @RequestMapping(value = "/{city}/country/{country}", method = RequestMethod.GET,
53 | produces = MediaType.APPLICATION_JSON_VALUE)
54 | @ResponseBody
55 | @Transactional(readOnly = true)
56 | public City getCity(@PathVariable("city") String city, @PathVariable("country") String country) {
57 | City result = this.cityService.getCity(city, country);
58 | if (result == null) {
59 | throw new CityNotFoundException();
60 | }
61 | return result;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/rest/HotelController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.web.rest;
18 |
19 | import com.springboot.demo.domain.City;
20 | import com.springboot.demo.domain.Hotel;
21 | import com.springboot.demo.domain.Rating;
22 | import com.springboot.demo.domain.Review;
23 | import com.springboot.demo.service.CityService;
24 | import com.springboot.demo.service.HotelService;
25 | import com.springboot.demo.service.ReviewsSummary;
26 | import com.springboot.demo.web.rest.dto.ReviewDetailsDto;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 | import org.springframework.beans.factory.annotation.Autowired;
30 | import org.springframework.beans.factory.annotation.Value;
31 | import org.springframework.data.domain.Page;
32 | import org.springframework.data.domain.PageRequest;
33 | import org.springframework.http.MediaType;
34 | import org.springframework.transaction.annotation.Transactional;
35 | import org.springframework.web.bind.annotation.*;
36 |
37 | import java.util.Map;
38 |
39 | @RestController
40 | @RequestMapping("/hotel")
41 | public class HotelController extends BaseController {
42 |
43 | private final Logger log = LoggerFactory.getLogger(HotelController.class);
44 |
45 | @Value("${cache.timeToLiveSeconds}")
46 | private String cacheTime;
47 |
48 | @Autowired
49 | private CityService cityService;
50 |
51 | @Autowired
52 | private HotelService hotelService;
53 |
54 | @RequestMapping(value = "/city/{city}/country/{country}/hotel/{hotel}", method = RequestMethod.GET,
55 | produces = MediaType.APPLICATION_JSON_VALUE)
56 | @ResponseBody
57 | @Transactional(readOnly = true)
58 | public Hotel getHotel(@PathVariable("city") String city,
59 | @PathVariable("country") String country, @PathVariable("hotel") String hotel) {
60 | final City citi = cityService.getCity(city, country);
61 | return this.hotelService.getHotel(citi, hotel);
62 | }
63 |
64 | @RequestMapping(value = "/city/{city}/country/{country}/hotel/{hotel}/review", method = RequestMethod.GET,
65 | produces = MediaType.APPLICATION_JSON_VALUE)
66 | @ResponseBody
67 | @Transactional(readOnly = true)
68 | public Page getHotelReview(@PathVariable("city") String city,
69 | @PathVariable("country") String country, @PathVariable("hotel") String hotel) {
70 | final City citi = cityService.getCity(city, country);
71 | PageRequest pageRequest = new PageRequest(0, 4);
72 | log.info("Cache time config value " + cacheTime);
73 | return this.hotelService.getReviews(this.hotelService.getHotel(citi, hotel), pageRequest);
74 | }
75 |
76 | @RequestMapping(value = "/city/{city}/country/{country}/hotel/{hotel}/review", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
77 | @ResponseBody
78 | public Review addHotelReview(@PathVariable("city") String city,
79 | @PathVariable("country") String country, @PathVariable("hotel") String hotel, @RequestBody
80 | ReviewDetailsDto reviewDetails) {
81 | final City citi = cityService.getCity(city, country);
82 | log.info("Review Details date : - " + reviewDetails.toString());
83 | return this.hotelService.addReview(this.hotelService.getHotel(citi, hotel), reviewDetails);
84 | }
85 |
86 | @RequestMapping(value = "/city/{city}/country/{country}/hotel/{hotel}/review_summary",
87 | method = RequestMethod.GET,
88 | produces = MediaType.APPLICATION_JSON_VALUE)
89 | @ResponseBody
90 | @Transactional(readOnly = true)
91 | public Long getReviewSummary(@PathVariable("city") String city,
92 | @PathVariable("country") String country, @PathVariable("hotel") String hotel) {
93 | final City citi = cityService.getCity(city, country);
94 | return this.hotelService.getReviewSummary(this.hotelService.getHotel(citi, hotel)).getNumberOfReviewsWithRating(Rating.AVERAGE);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/rest/LogsController.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.web.rest;
2 |
3 | import ch.qos.logback.classic.Level;
4 | import ch.qos.logback.classic.LoggerContext;
5 | import com.codahale.metrics.annotation.Timed;
6 | import com.springboot.demo.web.rest.dto.LoggerDTO;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.http.HttpStatus;
9 | import org.springframework.http.MediaType;
10 | import org.springframework.web.bind.annotation.*;
11 |
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | /**
16 | * Controller for view and managing Log Level at runtime.
17 | */
18 | @RestController
19 | @RequestMapping("/api")
20 | public class LogsController extends BaseController {
21 |
22 | @RequestMapping(value = "/logs",
23 | method = RequestMethod.GET,
24 | produces = MediaType.APPLICATION_JSON_VALUE)
25 | @Timed
26 | public List getList() {
27 | LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
28 | return context.getLoggerList()
29 | .stream()
30 | .map(LoggerDTO::new)
31 | .collect(Collectors.toList());
32 |
33 | }
34 |
35 | @RequestMapping(value = "/logs",
36 | method = RequestMethod.PUT)
37 | @ResponseStatus(HttpStatus.NO_CONTENT)
38 | @Timed
39 | public void changeLevel(@RequestBody LoggerDTO jsonLogger) {
40 | LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
41 | context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel()));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/rest/dto/LoggerDTO.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.web.rest.dto;
2 |
3 | import ch.qos.logback.classic.Logger;
4 | import com.fasterxml.jackson.annotation.JsonCreator;
5 |
6 | public class LoggerDTO {
7 |
8 | private String name;
9 |
10 | private String level;
11 |
12 | public LoggerDTO(Logger logger) {
13 | this.name = logger.getName();
14 | this.level = logger.getEffectiveLevel().toString();
15 | }
16 |
17 | @JsonCreator
18 | public LoggerDTO() {
19 | }
20 |
21 | public String getName() {
22 | return name;
23 | }
24 |
25 | public void setName(String name) {
26 | this.name = name;
27 | }
28 |
29 | public String getLevel() {
30 | return level;
31 | }
32 |
33 | public void setLevel(String level) {
34 | this.level = level;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return "LoggerDTO{" +
40 | "name='" + name + '\'' +
41 | ", level='" + level + '\'' +
42 | '}';
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/rest/dto/ReviewDetailsDto.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.springboot.demo.web.rest.dto;
18 |
19 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
20 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
21 | import com.springboot.demo.domain.Rating;
22 | import com.springboot.demo.domain.TripType;
23 | import com.springboot.demo.domain.util.CustomDateTimeDeserializer;
24 | import com.springboot.demo.domain.util.CustomDateTimeSerializer;
25 | import lombok.Data;
26 | import org.hibernate.annotations.Type;
27 | import org.joda.time.DateTime;
28 |
29 | import java.io.Serializable;
30 |
31 | @Data
32 | public class ReviewDetailsDto implements Serializable {
33 |
34 | private static final long serialVersionUID = 1L;
35 |
36 | private Rating rating;
37 |
38 | @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
39 | @JsonSerialize(using = CustomDateTimeSerializer.class)
40 | @JsonDeserialize(using = CustomDateTimeDeserializer.class)
41 | private DateTime checkInDate;
42 |
43 | private TripType tripType;
44 |
45 | private String title;
46 |
47 | private String details;
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/rest/errors/CityNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.web.rest.errors;
2 |
3 | /**
4 | * Created by neerajsi on 18/09/15.
5 | */
6 | public class CityNotFoundException extends RuntimeException {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/com/springboot/demo/web/rest/errors/CustomParameterizedException.java:
--------------------------------------------------------------------------------
1 | package com.springboot.demo.web.rest.errors;
2 |
3 | /**
4 | * Custom, parameterized exception, which can be translated on the client side.
5 | * For example:
6 | *
7 | *