Browse Source

2019/07/18

x1ongzhu 6 years ago
parent
commit
f6cd70a55d
32 changed files with 637 additions and 164 deletions
  1. 40 39
      src/main/java/com/izouma/walkchina/configuration/MiniAppConfig.java
  2. 2 0
      src/main/java/com/izouma/walkchina/configuration/RedisConfig.java
  3. 28 0
      src/main/java/com/izouma/walkchina/constant/AppConstants.java
  4. 15 0
      src/main/java/com/izouma/walkchina/constant/Strings.java
  5. 8 0
      src/main/java/com/izouma/walkchina/domain/JourneyStage.java
  6. 23 0
      src/main/java/com/izouma/walkchina/domain/JsApiTicket.java
  7. 1 1
      src/main/java/com/izouma/walkchina/domain/Message.java
  8. 3 0
      src/main/java/com/izouma/walkchina/domain/TeamMember.java
  9. 4 7
      src/main/java/com/izouma/walkchina/domain/WalkData.java
  10. 26 0
      src/main/java/com/izouma/walkchina/domain/WxAccessToken.java
  11. 0 21
      src/main/java/com/izouma/walkchina/dto/AppConstants.java
  12. 8 0
      src/main/java/com/izouma/walkchina/repo/JsApiTicketRepository.java
  13. 2 3
      src/main/java/com/izouma/walkchina/repo/TeamMemberRepository.java
  14. 7 0
      src/main/java/com/izouma/walkchina/repo/UserCoinRecordRepository.java
  15. 11 0
      src/main/java/com/izouma/walkchina/repo/WalkDataRepository.java
  16. 8 0
      src/main/java/com/izouma/walkchina/repo/WxAccessTokenRepository.java
  17. 1 1
      src/main/java/com/izouma/walkchina/security/JwtTokenUtil.java
  18. 96 20
      src/main/java/com/izouma/walkchina/service/JourneyService.java
  19. 2 36
      src/main/java/com/izouma/walkchina/service/MapService.java
  20. 114 0
      src/main/java/com/izouma/walkchina/service/TeamService.java
  21. 13 1
      src/main/java/com/izouma/walkchina/service/UserInfoService.java
  22. 12 0
      src/main/java/com/izouma/walkchina/utils/SecurityUtils.java
  23. 17 7
      src/main/java/com/izouma/walkchina/web/JourneyController.java
  24. 1 1
      src/main/java/com/izouma/walkchina/web/SystemVariableController.java
  25. 26 0
      src/main/java/com/izouma/walkchina/web/TeamController.java
  26. 10 1
      src/test/java/com/izouma/walkchina/CommonTest.java
  27. 36 0
      src/test/java/com/izouma/walkchina/repo/TeamMemberRepositoryTest.java
  28. 0 1
      src/test/java/com/izouma/walkchina/repo/WalkDataRepositoryTest.java
  29. 28 0
      src/test/java/com/izouma/walkchina/repo/WxAccessTokenRepositoryTest.java
  30. 42 0
      src/test/java/com/izouma/walkchina/service/JourneyServiceTest.java
  31. 11 25
      src/test/java/com/izouma/walkchina/service/MapServiceTest.java
  32. 42 0
      src/test/java/com/izouma/walkchina/service/WalkDataServiceTest.java

+ 40 - 39
src/main/java/com/izouma/walkchina/configuration/MiniAppConfig.java

@@ -2,18 +2,18 @@ package com.izouma.walkchina.configuration;
 
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
 import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
+import com.izouma.walkchina.domain.JsApiTicket;
+import com.izouma.walkchina.repo.JsApiTicketRepository;
+import com.izouma.walkchina.repo.WxAccessTokenRepository;
 import lombok.Data;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.PostConstruct;
 import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Date;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -21,11 +21,11 @@ import java.util.concurrent.locks.ReentrantLock;
 @Component
 @ConfigurationProperties(prefix = "wx.miniapp")
 public class MiniAppConfig implements WxMaConfig {
-    private final String MA_ACCESS_TOKEN_REDIS_KEY = "miniAppAccessToken";
-    private final String MA_JSAPI_TICKET_REDIS_KEY = "miniAppJsapiTicket";
 
     @Autowired
-    private RedisTemplate redisTemplate;
+    private WxAccessTokenRepository wxAccessTokenRepository;
+    @Autowired
+    private JsApiTicketRepository   jsApiTicketRepository;
 
     private String appId;
     private String appSecret;
@@ -54,10 +54,11 @@ public class MiniAppConfig implements WxMaConfig {
 
     @Override
     public String getAccessToken() {
-        try {
-            Map<String, Object> map = (Map<String, Object>) redisTemplate.opsForValue().get(MA_ACCESS_TOKEN_REDIS_KEY);
-            return (String) map.get("accessToken");
-        } catch (Exception ignored) {
+        com.izouma.walkchina.domain.WxAccessToken wxAccessToken = wxAccessTokenRepository.findByAppId(appId);
+        if (wxAccessToken != null) {
+            if (!new Date(wxAccessToken.getExpiresAt()).before(new Date())) {
+                return wxAccessToken.getToken();
+            }
         }
         return null;
     }
@@ -73,7 +74,11 @@ public class MiniAppConfig implements WxMaConfig {
 
     @Override
     public boolean isAccessTokenExpired() {
-        return isExpired(MA_ACCESS_TOKEN_REDIS_KEY);
+        com.izouma.walkchina.domain.WxAccessToken wxAccessToken = wxAccessTokenRepository.findByAppId(appId);
+        if (wxAccessToken != null) {
+            return new Date(wxAccessToken.getExpiresAt()).before(new Date());
+        }
+        return true;
     }
 
     @Override
@@ -84,18 +89,21 @@ public class MiniAppConfig implements WxMaConfig {
     @Override
     public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
         long expiresAt = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
-        Map<String, Object> map = new HashMap<>();
-        map.put("accessToken", accessToken);
-        map.put("expiresAt", expiresAt);
-        redisTemplate.opsForValue().set(MA_ACCESS_TOKEN_REDIS_KEY, map);
+        com.izouma.walkchina.domain.WxAccessToken wxAccessToken = wxAccessTokenRepository.findByAppId(appId);
+        if (wxAccessToken != null) {
+            wxAccessTokenRepository.delete(wxAccessToken);
+        }
+        wxAccessToken = new com.izouma.walkchina.domain.WxAccessToken(appId, accessToken, expiresAt);
+        wxAccessTokenRepository.save(wxAccessToken);
     }
 
     @Override
     public String getJsapiTicket() {
-        try {
-            Map<String, Object> map = (Map<String, Object>) redisTemplate.opsForValue().get(MA_JSAPI_TICKET_REDIS_KEY);
-            return (String) map.get("ticket");
-        } catch (Exception ignored) {
+        JsApiTicket jsApiTicket = jsApiTicketRepository.findByAppId(appId);
+        if (jsApiTicket != null) {
+            if (!new Date(jsApiTicket.getExpiresAt()).before(new Date())) {
+                return jsApiTicket.getTicket();
+            }
         }
         return null;
     }
@@ -107,31 +115,25 @@ public class MiniAppConfig implements WxMaConfig {
 
     @Override
     public boolean isJsapiTicketExpired() {
-        return isExpired(MA_JSAPI_TICKET_REDIS_KEY);
-    }
-
-    private boolean isExpired(String redisKey) {
-        try {
-            Map<String, Object> map = (Map<String, Object>) redisTemplate.opsForValue().get(redisKey);
-            long expiresAt = (long) map.get("expiresAt");
-            return System.currentTimeMillis() >= expiresAt;
-        } catch (Exception ignored) {
+        com.izouma.walkchina.domain.JsApiTicket jsApiTicket = jsApiTicketRepository.findByAppId(appId);
+        if (jsApiTicket != null) {
+            return new Date(jsApiTicket.getExpiresAt()).before(new Date());
         }
         return true;
     }
 
     @Override
     public void expireJsapiTicket() {
-        redisTemplate.delete(MA_JSAPI_TICKET_REDIS_KEY);
+        jsApiTicketRepository.delete(new JsApiTicket(appId, null, null));
     }
 
     @Override
     public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
         long expiresAt = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
-        Map<String, Object> map = new HashMap<>();
-        map.put("ticket", jsapiTicket);
-        map.put("expiresAt", expiresAt);
-        redisTemplate.opsForValue().set(MA_JSAPI_TICKET_REDIS_KEY, map);
+        com.izouma.walkchina.domain.JsApiTicket jsApiTicket = jsApiTicketRepository.findByAppId(appId);
+        jsApiTicketRepository.delete(jsApiTicket);
+        jsApiTicket = new com.izouma.walkchina.domain.JsApiTicket(appId, jsapiTicket, expiresAt);
+        jsApiTicketRepository.save(jsApiTicket);
     }
 
 
@@ -164,7 +166,7 @@ public class MiniAppConfig implements WxMaConfig {
 
     @Override
     public void expireAccessToken() {
-        redisTemplate.delete(MA_ACCESS_TOKEN_REDIS_KEY);
+        wxAccessTokenRepository.delete(new com.izouma.walkchina.domain.WxAccessToken(appId, null, null));
     }
 
     @Override
@@ -179,10 +181,9 @@ public class MiniAppConfig implements WxMaConfig {
 
     @Override
     public long getExpiresTime() {
-        try {
-            Map<String, Object> map = (Map<String, Object>) redisTemplate.opsForValue().get(MA_ACCESS_TOKEN_REDIS_KEY);
-            return (long) map.get("expiresAt");
-        } catch (Exception ignored) {
+        com.izouma.walkchina.domain.WxAccessToken wxAccessToken = wxAccessTokenRepository.findByAppId(appId);
+        if (wxAccessToken != null) {
+            return wxAccessToken.getExpiresAt();
         }
         return 0;
     }

+ 2 - 0
src/main/java/com/izouma/walkchina/configuration/RedisConfig.java

@@ -9,11 +9,13 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 @Configuration
 @AutoConfigureAfter(RedisAutoConfiguration.class)
+@EnableRedisRepositories
 public class RedisConfig {
 
     @Bean

+ 28 - 0
src/main/java/com/izouma/walkchina/constant/AppConstants.java

@@ -0,0 +1,28 @@
+package com.izouma.walkchina.constant;
+
+import java.util.Date;
+
+public interface AppConstants {
+    String DEFAULT_AVATAR = "https://microball.oss-cn-hangzhou.aliyuncs.com/awesomeAdmin/user.png";
+
+    double STEP_TO_DISTANCE_RATE = 1;  // 1步=多少米
+    double DISTANCE_TO_COIN_RATE = 0.01; // 1米=多少商城币
+    double HIRE_PRICE_RATE       = 0.00001; // 1步=多少身价
+
+    Date FOREVER = new Date(32472115200000L);
+
+    interface MessageType {
+        int NORMAL          = 1;
+        int TEAM            = 2;
+        int PROGRESS_UPDATE = 3;
+    }
+
+    interface CoinRecordType {
+        int STAGE    = 1; // 领取阶段奖励
+        int STEAL    = 2; // 偷奖金
+        int ARRIVAL  = 3; // 到达城市
+        int HIRE     = 4; // 雇佣
+        int BE_HIRED = 5; // 被雇佣
+        int BUY      = 6; // 购买商品
+    }
+}

+ 15 - 0
src/main/java/com/izouma/walkchina/constant/Strings.java

@@ -0,0 +1,15 @@
+package com.izouma.walkchina.constant;
+
+public interface Strings {
+    String MSG_JOURNEY_PROGRESS = "你正在从 %s 向 %s 前进,你今日步数%s步,已行走%s天,共%d步,已完成进度%d%%";
+
+    String MSG_HIRE = "你使用%.2f商城币雇佣了%s";
+
+    String MSG_HIRED = "%s使用%.2f商城币雇佣了你";
+
+    String MSG_MEMBER_GRABBED = "你的队员%s,被%s抢走了";
+
+    String REMARK_HIRE = "雇佣队员";
+
+    String REMARK_BE_HIRED = "队员佣金";
+}

+ 8 - 0
src/main/java/com/izouma/walkchina/domain/JourneyStage.java

@@ -14,6 +14,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 
 import javax.persistence.*;
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
 
@@ -39,6 +40,11 @@ public class JourneyStage implements Serializable {
 
     private Long destinationId;
 
+    @Column(precision = 10, scale = 2)
+    private BigDecimal award;
+
+    private Date finishAt;
+
     @Lob
     @Column(length = 100000)
     @Convert(converter = DoubleArrayConverter.class)
@@ -50,6 +56,8 @@ public class JourneyStage implements Serializable {
 
     private Long currentSteps;
 
+    private Long stepOffset;
+
     @Lob
     @Column(length = 100000)
     @Convert(converter = RouteStepConverter.class)

+ 23 - 0
src/main/java/com/izouma/walkchina/domain/JsApiTicket.java

@@ -0,0 +1,23 @@
+package com.izouma.walkchina.domain;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import org.springframework.data.redis.core.RedisHash;
+
+@Data
+@NoArgsConstructor
+@ToString
+@RedisHash("JsApiTicket")
+public class JsApiTicket {
+    private String id;
+    private String appId;
+    private String ticket;
+    private Long   expiresAt;
+
+    public JsApiTicket(String appId, String ticket, Long expiresAt) {
+        this.appId = appId;
+        this.ticket = ticket;
+        this.expiresAt = expiresAt;
+    }
+}

+ 1 - 1
src/main/java/com/izouma/walkchina/domain/Message.java

@@ -1,7 +1,7 @@
 package com.izouma.walkchina.domain;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
-import com.izouma.walkchina.dto.AppConstants;
+import com.izouma.walkchina.constant.AppConstants;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;

+ 3 - 0
src/main/java/com/izouma/walkchina/domain/TeamMember.java

@@ -32,6 +32,9 @@ public class TeamMember {
 
     private Long leader;
 
+    @Temporal(TemporalType.DATE)
+    private Date hireDate;
+
     @Temporal(TemporalType.DATE)
     private Date startDate;
 

+ 4 - 7
src/main/java/com/izouma/walkchina/domain/WalkData.java

@@ -1,8 +1,10 @@
 package com.izouma.walkchina.domain;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
-import lombok.*;
-import org.hibernate.annotations.Where;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 import org.springframework.data.annotation.CreatedBy;
 import org.springframework.data.annotation.CreatedDate;
 import org.springframework.data.annotation.LastModifiedBy;
@@ -18,7 +20,6 @@ import java.util.Date;
 @AllArgsConstructor
 @Builder
 @JsonInclude(JsonInclude.Include.NON_NULL)
-@Where(clause = "active = 1")
 @EntityListeners(AuditingEntityListener.class)
 public class WalkData {
 
@@ -33,10 +34,6 @@ public class WalkData {
     @Temporal(TemporalType.DATE)
     private Date date;
 
-    @Column(columnDefinition = "bit default 1", nullable = false)
-    @Builder.Default
-    public Boolean active = true;
-
     @CreatedBy
     private String createdBy;
 

+ 26 - 0
src/main/java/com/izouma/walkchina/domain/WxAccessToken.java

@@ -0,0 +1,26 @@
+package com.izouma.walkchina.domain;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import org.springframework.data.redis.core.RedisHash;
+
+import javax.persistence.Id;
+
+@Data
+@NoArgsConstructor
+@ToString
+@RedisHash("WxAccessToken")
+public class WxAccessToken {
+    @Id
+    private String id;
+    private String appId;
+    private String token;
+    private Long   expiresAt;
+
+    public WxAccessToken(String appId, String token, Long expiresAt) {
+        this.appId = appId;
+        this.token = token;
+        this.expiresAt = expiresAt;
+    }
+}

+ 0 - 21
src/main/java/com/izouma/walkchina/dto/AppConstants.java

@@ -1,21 +0,0 @@
-package com.izouma.walkchina.dto;
-
-public interface AppConstants {
-    String DEFAULT_AVATAR = "https://microball.oss-cn-hangzhou.aliyuncs.com/awesomeAdmin/user.png";
-
-    double STEP_TO_DISTANCE_RATE = 1;  // 1步=多少米
-    double DISTANCE_TO_COIN_RATE = 0.01; // 1米=多少商城币
-
-    interface MessageType {
-        int NORMAL = 1;
-        int TEAM   = 2;
-    }
-
-    interface CoinRecordType {
-        int STAGE   = 1; // 领取阶段奖励
-        int STEAL   = 2; // 偷奖金
-        int ARRIVAL = 3; // 到达城市
-        int EMPLOY  = 4; // 雇佣
-        int BUY     = 5; // 购买商品
-    }
-}

+ 8 - 0
src/main/java/com/izouma/walkchina/repo/JsApiTicketRepository.java

@@ -0,0 +1,8 @@
+package com.izouma.walkchina.repo;
+
+import com.izouma.walkchina.domain.JsApiTicket;
+import org.springframework.data.repository.CrudRepository;
+
+public interface JsApiTicketRepository extends CrudRepository<JsApiTicket, String> {
+    JsApiTicket findByAppId(String appId);
+}

+ 2 - 3
src/main/java/com/izouma/walkchina/repo/TeamMemberRepository.java

@@ -5,10 +5,9 @@ import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Query;
 
 import java.util.Date;
-import java.util.List;
 
 public interface TeamMemberRepository extends JpaRepository<TeamMember, Long> {
 
-    @Query("select t from TeamMember t where t.leader = ?1 and t.startDate >= ?2 and t.endDate <= ?2")
-    List<TeamMember> findUserTeamMembers(Long leader, Date date);
+    @Query("select TeamMember from TeamMember t where t.userId = ?1 and t.startDate <= ?2 and t.endDate >= ?2")
+    TeamMember findActive(Long userId, Date date);
 }

+ 7 - 0
src/main/java/com/izouma/walkchina/repo/UserCoinRecordRepository.java

@@ -0,0 +1,7 @@
+package com.izouma.walkchina.repo;
+
+import com.izouma.walkchina.domain.UserCoinRecord;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface UserCoinRecordRepository extends JpaRepository<UserCoinRecord, Long> {
+}

+ 11 - 0
src/main/java/com/izouma/walkchina/repo/WalkDataRepository.java

@@ -7,6 +7,7 @@ import org.springframework.data.jpa.repository.Query;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Date;
+import java.util.Optional;
 
 public interface WalkDataRepository extends JpaRepository<WalkData, Long> {
     WalkData findByUserIdAndDate(Long userId, Date date);
@@ -16,4 +17,14 @@ public interface WalkDataRepository extends JpaRepository<WalkData, Long> {
     @Query(value = "UPDATE user_info SET total_steps = (SELECT SUM(steps) FROM walk_data WHERE user_id = ?1 AND walk_data.active = 1) WHERE id = ?1", nativeQuery = true)
     int updateUserSteps(Long userId);
 
+
+    @Query(value = "SELECT SUM(walk_data.steps) FROM team_member " +
+            "JOIN walk_data ON team_member.user_id = walk_data.user_id " +
+            "AND walk_data.date >= team_member.start_date " +
+            "AND walk_data.date <= team_member.end_date " +
+            "WHERE leader = ?1 AND walk_data.date >= ?2 AND walk_data.date <= ?3", nativeQuery = true)
+    Optional<Integer> sumTeamWalkSteps(Long userId, Date start, Date end);
+
+    @Query(value = "SELECT SUM(steps) FROM walk_data WHERE user_id = ?1 AND date >= ?2 AND date <= ?3", nativeQuery = true)
+    Optional<Integer> sumUserWalkSteps(Long userId, Date start, Date end);
 }

+ 8 - 0
src/main/java/com/izouma/walkchina/repo/WxAccessTokenRepository.java

@@ -0,0 +1,8 @@
+package com.izouma.walkchina.repo;
+
+import com.izouma.walkchina.domain.WxAccessToken;
+import org.springframework.data.repository.CrudRepository;
+
+public interface WxAccessTokenRepository extends CrudRepository<WxAccessToken, String> {
+    WxAccessToken findByAppId(String appId);
+}

+ 1 - 1
src/main/java/com/izouma/walkchina/security/JwtTokenUtil.java

@@ -19,7 +19,7 @@ public class JwtTokenUtil implements Serializable {
 
     private static final long serialVersionUID = -3722940977538012340L;
 
-    public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;
+    public static final long JWT_TOKEN_VALIDITY = 60 * 60 * 24 * 30;
 
     @Value("${jwt.secret}")
     private String secret;

+ 96 - 20
src/main/java/com/izouma/walkchina/service/JourneyService.java

@@ -1,7 +1,11 @@
 package com.izouma.walkchina.service;
 
-import com.izouma.walkchina.dto.AppConstants;
+import com.izouma.walkchina.constant.AppConstants;
 import com.izouma.walkchina.domain.*;
+import com.izouma.walkchina.dto.Location;
+import com.izouma.walkchina.constant.Strings;
+import com.izouma.walkchina.dto.webservice.DirectionResponse;
+import com.izouma.walkchina.dto.webservice.MapRoute;
 import com.izouma.walkchina.exception.ServiceException;
 import com.izouma.walkchina.repo.*;
 import org.joda.time.Days;
@@ -9,8 +13,10 @@ import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
+import java.util.Optional;
 
 @Service
 public class JourneyService {
@@ -24,11 +30,86 @@ public class JourneyService {
     private TeamMemberRepository   teamMemberRepository;
     @Autowired
     private MessageRepository      messageRepository;
+    @Autowired
+    private CityRepository         cityRepository;
+    @Autowired
+    private MapService             mapService;
 
     public boolean hasJourney(Long userId) {
         return userJourneyRepository.findByUserId(userId) != null;
     }
 
+    public void newJourney(Long userId, Long originId, Long destinationId) {
+        City origin = cityRepository.findById(originId).orElse(null);
+        if (origin == null) {
+            throw new ServiceException("起始地不存在");
+        }
+        City destination = cityRepository.findById(destinationId).orElse(null);
+        if (destination == null) {
+            throw new ServiceException("目的地不存在");
+        }
+        DirectionResponse directionResponse = mapService.direction(new Location(origin.getLatitude(), origin.getLongitude()),
+                new Location(destination.getLatitude(), destination.getLongitude()));
+        if (directionResponse.getStatus() != 0) {
+            throw new ServiceException(directionResponse.getMessage());
+        }
+        UserJourney userJourney = UserJourney.builder()
+                .userId(userId)
+                .originId(originId)
+                .destinationId(destinationId)
+                .distance(directionResponse.getResult().getRoutes().get(0).getDistance())
+                .polyline(directionResponse.getResult().getRoutes().get(0).getPolyline())
+                .build();
+        userJourney = userJourneyRepository.save(userJourney);
+        int distance = directionResponse.getResult().getRoutes().get(0).getDistance();
+        JourneyStage journeyStage = JourneyStage.builder()
+                .userId(userId)
+                .journeyId(userJourney.getId())
+                .originId(originId)
+                .destinationId(destinationId)
+                .polyline(directionResponse.getResult().getRoutes().get(0).getPolyline())
+                .routeSteps(directionResponse.getResult().getRoutes().get(0).getSteps())
+                .distance(directionResponse.getResult().getRoutes().get(0).getDistance())
+                .progress(.0)
+                .steps(Math.round(distance / AppConstants.STEP_TO_DISTANCE_RATE))
+                .award(BigDecimal.valueOf(Math.round(distance * AppConstants.DISTANCE_TO_COIN_RATE)))
+                .build();
+        journeyStage = journeyStageRepository.save(journeyStage);
+    }
+
+    public void newDestination(Long userId, Long id) {
+        City destination = cityRepository.findById(id).orElse(null);
+        if (destination == null) {
+            throw new ServiceException("目的地不存在");
+        }
+        UserJourney userJourney = userJourneyRepository.findByUserId(userId);
+        JourneyStage journeyStage = journeyStageRepository.findByUserIdAndJourneyIdOrderByIdDesc(userId, userJourney.getId());
+        DirectionResponse directionResponse = mapService.direction(new Location(journeyStage.getDestination().getLatitude(), journeyStage.getDestination().getLongitude()),
+                new Location(destination.getLatitude(), destination.getLongitude()));
+        if (directionResponse.getStatus() != 0) {
+            throw new ServiceException(directionResponse.getMessage());
+        }
+
+        MapRoute route = directionResponse.getResult().getRoutes().get(0);
+
+        JourneyStage newStage = JourneyStage.builder()
+                .userId(userId)
+                .journeyId(userJourney.getId())
+                .originId(journeyStage.getDestination().getId())
+                .destinationId(destination.getId())
+                .distance(route.getDistance())
+                .progress(.0)
+                .polyline(route.getPolyline())
+                .routeSteps(route.getSteps())
+                .build();
+        newStage = journeyStageRepository.save(newStage);
+        List<Double> polyline = mapService.extractPolyline(userJourney.getPolyline());
+        route.getPolyline().set(0, route.getPolyline().get(0) * 1000000 - polyline.get(polyline.size() - 2) * 1000000);
+        route.getPolyline().set(1, route.getPolyline().get(1) * 1000000 - polyline.get(polyline.size() - 1) * 1000000);
+        userJourney.getPolyline().addAll(route.getPolyline());
+        userJourneyRepository.save(userJourney);
+    }
+
     public void updateUserJourney(Long userId, Date date) {
         UserJourney userJourney = userJourneyRepository.findByUserId(userId);
         if (userJourney == null) {
@@ -39,21 +120,14 @@ public class JourneyService {
             throw new ServiceException("无数据");
         }
         JourneyStage latestStage = stageList.get(stageList.size() - 1);
-        if (latestStage.getProgress() != 1) {
-
-        }
         Long steps = 0L;
-        WalkData walkData = walkDataRepository.findByUserIdAndDate(userId, date);
-        if (walkData != null) {
-            steps += walkData.getSteps();
-        }
-        List<TeamMember> teamMembers = teamMemberRepository.findUserTeamMembers(userId, date);
-        for (TeamMember teamMember : teamMembers) {
-            WalkData w = walkDataRepository.findByUserIdAndDate(teamMember.getUserId(), date);
-            if (w != null) {
-                steps += w.getSteps();
-            }
-        }
+        WalkData todayWalkData = walkDataRepository.findByUserIdAndDate(userId, date);
+
+        steps += walkDataRepository.sumTeamWalkSteps(userId, latestStage.getCreatedAt(),
+                Optional.of(latestStage.getFinishAt()).orElse(new Date()))
+                .orElse(0);
+
+
         latestStage.setSteps(steps);
         double progress = steps * AppConstants.STEP_TO_DISTANCE_RATE / latestStage.getDistance();
         progress = progress > 1 ? 1 : progress;
@@ -63,11 +137,13 @@ public class JourneyService {
         if (progress == 1) {
             Message msg = Message.builder()
                     .userId(userId)
-                    .content("你正在从 " + latestStage.getOrigin().getName()
-                            + " 向 " + latestStage.getDestination().getName()
-                            + " 前进,你今日步数"
-                            + (walkData != null ? walkData.getSteps() : 0)
-                            + "步,已行走" + calcDays(latestStage.getCreatedAt(), new Date()))
+                    .content(String.format(Strings.MSG_JOURNEY_PROGRESS,
+                            latestStage.getOrigin().getName(),
+                            latestStage.getDestination().getName(),
+                            (todayWalkData != null ? todayWalkData.getSteps() : 0),
+                            calcDays(latestStage.getCreatedAt(), new Date()),
+                            steps,
+                            Math.round(progress * 100)))
                     .build();
             messageRepository.save(msg);
         }

+ 2 - 36
src/main/java/com/izouma/walkchina/service/MapService.java

@@ -2,12 +2,12 @@ package com.izouma.walkchina.service;
 
 import com.github.kevinsawicki.http.HttpRequest;
 import com.google.gson.Gson;
+import com.izouma.walkchina.constant.AppConstants;
 import com.izouma.walkchina.domain.City;
 import com.izouma.walkchina.domain.JourneyStage;
 import com.izouma.walkchina.domain.UserJourney;
 import com.izouma.walkchina.dto.*;
 import com.izouma.walkchina.dto.webservice.DirectionResponse;
-import com.izouma.walkchina.dto.webservice.MapRoute;
 import com.izouma.walkchina.dto.webservice.RouteStep;
 import com.izouma.walkchina.exception.ServiceException;
 import com.izouma.walkchina.repo.*;
@@ -20,11 +20,10 @@ import org.springframework.stereotype.Service;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.*;
-import java.util.function.Supplier;
 
 @Service
 @Slf4j
-public class MapService implements Supplier<ServiceException> {
+public class MapService   {
     @Autowired
     private CityRepository         cityRepository;
     @Autowired
@@ -123,39 +122,6 @@ public class MapService implements Supplier<ServiceException> {
         return userMap;
     }
 
-    public void newDestination(Long userId, Long id) {
-        City destination = cityRepository.findById(id).orElse(null);
-        if (destination == null) {
-            throw new ServiceException("目的地不存在");
-        }
-        UserJourney userJourney = userJourneyRepository.findByUserId(userId);
-        JourneyStage journeyStage = journeyStageRepository.findByUserIdAndJourneyIdOrderByIdDesc(userId, userJourney.getId());
-        DirectionResponse directionResponse = direction(new Location(journeyStage.getDestination().getLatitude(), journeyStage.getDestination().getLongitude()),
-                new Location(destination.getLatitude(), destination.getLongitude()));
-        MapRoute route = directionResponse.getResult().getRoutes().get(0);
-
-        JourneyStage newStage = JourneyStage.builder()
-                .userId(userId)
-                .journeyId(userJourney.getId())
-                .originId(journeyStage.getDestination().getId())
-                .destinationId(destination.getId())
-                .distance(route.getDistance())
-                .progress(.0)
-                .polyline(route.getPolyline())
-                .routeSteps(route.getSteps())
-                .build();
-        newStage = journeyStageRepository.save(newStage);
-        List<Double> polyline = extractPolyline(userJourney.getPolyline());
-        route.getPolyline().set(0, route.getPolyline().get(0) * 1000000 - polyline.get(polyline.size() - 2) * 1000000);
-        route.getPolyline().set(1, route.getPolyline().get(1) * 1000000 - polyline.get(polyline.size() - 1) * 1000000);
-        userJourney.getPolyline().addAll(route.getPolyline());
-        userJourneyRepository.save(userJourney);
-    }
-
-    @Override
-    public ServiceException get() {
-        return new ServiceException("");
-    }
 
     List<Double> extractPolyline(List<Double> polyline) {
         List<Double> list = new ArrayList<>(polyline);

+ 114 - 0
src/main/java/com/izouma/walkchina/service/TeamService.java

@@ -0,0 +1,114 @@
+package com.izouma.walkchina.service;
+
+import com.izouma.walkchina.constant.Strings;
+import com.izouma.walkchina.domain.Message;
+import com.izouma.walkchina.domain.TeamMember;
+import com.izouma.walkchina.domain.UserCoinRecord;
+import com.izouma.walkchina.domain.UserInfo;
+import com.izouma.walkchina.constant.AppConstants;
+import com.izouma.walkchina.exception.ServiceException;
+import com.izouma.walkchina.repo.MessageRepository;
+import com.izouma.walkchina.repo.TeamMemberRepository;
+import com.izouma.walkchina.repo.UserCoinRecordRepository;
+import com.izouma.walkchina.repo.UserInfoRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.Optional;
+
+@Service
+@Slf4j
+public class TeamService {
+    @Autowired
+    private TeamMemberRepository     teamMemberRepository;
+    @Autowired
+    private UserInfoRepository       userInfoRepository;
+    @Autowired
+    private UserCoinRecordRepository userCoinRecordRepository;
+    @Autowired
+    private MessageRepository        messageRepository;
+
+    public void hire(Long userId, Long target) {
+        Date now = new Date();
+        UserInfo userInfo = userInfoRepository.findById(userId).orElse(null);
+        if (userInfo == null) {
+            throw new ServiceException("用户不存在");
+        }
+        UserInfo targetUserInfo = userInfoRepository.findById(target).orElse(null);
+        if (targetUserInfo == null) {
+            throw new ServiceException("用户不存在");
+        }
+        TeamMember teamMember = teamMemberRepository.findActive(target, now);
+        if (teamMember != null) {
+            teamMember.setEndDate(now);
+            teamMemberRepository.save(teamMember);
+            Message grabMsg = Message.builder()
+                    .userId(teamMember.getLeader())
+                    .type(AppConstants.MessageType.NORMAL)
+                    .content(String.format(Strings.MSG_MEMBER_GRABBED, targetUserInfo.getNickname(),userInfo.getNickname()))
+                    .active(true)
+                    .isRead(false)
+                    .build();
+            messageRepository.save(grabMsg);
+        }
+
+        BigDecimal price = BigDecimal.valueOf(Optional.of(targetUserInfo.getTotalSteps()).orElse(0L)).multiply(BigDecimal.valueOf(AppConstants.HIRE_PRICE_RATE));
+        BigDecimal balance = Optional.of(userInfo.getCoin()).orElse(BigDecimal.ZERO);
+        if (balance.compareTo(price) < 0) {
+            throw new ServiceException("雇佣失败,商城币不足");
+        }
+
+        balance = balance.subtract(price);
+        userInfo.setCoin(balance);
+        userInfoRepository.save(userInfo);
+
+        TeamMember newTeamMember = TeamMember.builder()
+                .userId(target)
+                .leader(userId)
+                .hireDate(now)
+                .startDate(DateUtils.addDays(now, 1))
+                .endDate(AppConstants.FOREVER)
+                .active(true)
+                .build();
+        teamMemberRepository.save(newTeamMember);
+
+        UserCoinRecord hireRecord = UserCoinRecord.builder()
+                .userId(userId)
+                .modify(price.negate())
+                .balance(balance)
+                .type(AppConstants.CoinRecordType.HIRE)
+                .remark(Strings.REMARK_HIRE)
+                .build();
+        userCoinRecordRepository.save(hireRecord);
+        Message hireMsg = Message.builder()
+                .userId(userId)
+                .type(AppConstants.MessageType.NORMAL)
+                .content(String.format(Strings.MSG_HIRE, price, targetUserInfo.getNickname()))
+                .active(true)
+                .isRead(false)
+                .build();
+        messageRepository.save(hireMsg);
+
+        BigDecimal targetBalance = Optional.of(targetUserInfo.getCoin()).orElse(BigDecimal.ZERO).add(price);
+        UserCoinRecord beHiredRecord = UserCoinRecord.builder()
+                .userId(target)
+                .modify(price)
+                .balance(targetBalance)
+                .type(AppConstants.CoinRecordType.BE_HIRED)
+                .remark(Strings.REMARK_BE_HIRED)
+                .build();
+        userCoinRecordRepository.save(beHiredRecord);
+        Message beHireMsg = Message.builder()
+                .userId(userId)
+                .type(AppConstants.MessageType.NORMAL)
+                .content(String.format(Strings.MSG_HIRED, targetUserInfo.getNickname(), price))
+                .active(true)
+                .isRead(false)
+                .build();
+        messageRepository.save(beHireMsg);
+    }
+}

+ 13 - 1
src/main/java/com/izouma/walkchina/service/UserInfoService.java

@@ -3,13 +3,14 @@ package com.izouma.walkchina.service;
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
 import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
-import com.izouma.walkchina.dto.AppConstants;
+import com.izouma.walkchina.constant.AppConstants;
 import com.izouma.walkchina.domain.UserFriend;
 import com.izouma.walkchina.domain.UserInfo;
 import com.izouma.walkchina.exception.ServiceException;
 import com.izouma.walkchina.repo.UserFriendRepository;
 import com.izouma.walkchina.repo.UserInfoRepository;
 import com.izouma.walkchina.service.storage.StorageService;
+import com.izouma.walkchina.utils.ImageUtils;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.apache.commons.lang3.RandomStringUtils;
@@ -77,6 +78,7 @@ public class UserInfoService implements UserDetailsService {
                     .active(true)
                     .sessionKey(sessionKey)
                     .build();
+            uploadUserMarker(userInfo);
             return userInfoRepository.save(userInfo);
         } catch (WxErrorException e) {
             e.printStackTrace();
@@ -131,6 +133,7 @@ public class UserInfoService implements UserDetailsService {
         }
 
         if (userInfo != null) {
+            uploadUserMarker(userInfo);
             return userInfo;
         }
 
@@ -157,4 +160,13 @@ public class UserInfoService implements UserDetailsService {
         userInfo.setLongitude(longitude);
         userInfoRepository.save(userInfo);
     }
+
+    private void uploadUserMarker(UserInfo userInfo) {
+        try {
+            storageService.uploadFromInputStream(ImageUtils.getInputStream(ImageUtils.makeMarker("user", userInfo.getAvatar()), "png"), "marker/user/" + userInfo.getId() + ".png");
+            storageService.uploadFromInputStream(ImageUtils.getInputStream(ImageUtils.makeMarker("location", userInfo.getAvatar()), "png"), "marker/location/" + userInfo.getId() + ".png");
+        } catch (Exception e) {
+            log.error("upload marker", e);
+        }
+    }
 }

+ 12 - 0
src/main/java/com/izouma/walkchina/utils/SecurityUtils.java

@@ -0,0 +1,12 @@
+package com.izouma.walkchina.utils;
+
+import com.izouma.walkchina.domain.UserInfo;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+public class SecurityUtils {
+    public static UserInfo getAuthenticatedUser() {
+        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+        return (UserInfo) authentication.getPrincipal();
+    }
+}

+ 17 - 7
src/main/java/com/izouma/walkchina/web/JourneyController.java

@@ -3,12 +3,9 @@ package com.izouma.walkchina.web;
 import com.izouma.walkchina.domain.UserInfo;
 import com.izouma.walkchina.dto.Result;
 import com.izouma.walkchina.service.JourneyService;
+import com.izouma.walkchina.utils.SecurityUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @RestController
 @RequestMapping("/journey")
@@ -18,12 +15,25 @@ public class JourneyController {
 
     @GetMapping("/hasJourney")
     public Result hasJourney() {
-        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
-        UserInfo userInfo = (UserInfo) authentication.getPrincipal();
+        UserInfo userInfo = SecurityUtils.getAuthenticatedUser();
         if (journeyService.hasJourney(userInfo.getId())) {
             return Result.ok();
         } else {
             return Result.error();
         }
     }
+
+    @PostMapping("/newJourney")
+    public Result newJourney(@RequestParam("originId") Long originId, @RequestParam("destinationId") Long destinationId) {
+        UserInfo userInfo = SecurityUtils.getAuthenticatedUser();
+        journeyService.newJourney(userInfo.getId(), originId, destinationId);
+        return Result.ok();
+    }
+
+    @PostMapping("/newDestination")
+    public Result newDestination(@RequestParam("destinationId") Long destinationId) {
+        UserInfo userInfo = SecurityUtils.getAuthenticatedUser();
+        journeyService.newDestination(userInfo.getId(), destinationId);
+        return Result.ok();
+    }
 }

+ 1 - 1
src/main/java/com/izouma/walkchina/web/SystemVariableController.java

@@ -1,6 +1,6 @@
 package com.izouma.walkchina.web;
 
-import com.izouma.walkchina.dto.AppConstants;
+import com.izouma.walkchina.constant.AppConstants;
 import com.izouma.walkchina.dto.Result;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;

+ 26 - 0
src/main/java/com/izouma/walkchina/web/TeamController.java

@@ -0,0 +1,26 @@
+package com.izouma.walkchina.web;
+
+import com.izouma.walkchina.domain.UserInfo;
+import com.izouma.walkchina.dto.Result;
+import com.izouma.walkchina.service.TeamService;
+import com.izouma.walkchina.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/team")
+public class TeamController {
+
+    @Autowired
+    private TeamService teamService;
+
+    @PostMapping("/hire")
+    public Result hire(@RequestParam("target") Long target) {
+        UserInfo userInfo = SecurityUtils.getAuthenticatedUser();
+        teamService.hire(userInfo.getId(), target);
+        return Result.ok();
+    }
+}

+ 10 - 1
src/test/java/com/izouma/walkchina/CommonTest.java

@@ -8,6 +8,8 @@ import org.junit.Test;
 import javax.imageio.ImageIO;
 import java.io.File;
 import java.io.IOException;
+import java.math.BigDecimal;
+import java.text.MessageFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -27,5 +29,12 @@ public class CommonTest {
         ImageIO.write(ImageUtils.makeMarker("location", "https://ws1.sinaimg.cn/large/0065oQSqgy1fze94uew3jj30qo10cdka.jpg"), "png", new File("image.png"));
     }
 
-
+    @Test
+    public void testStringFmt() {
+        String string = String.format("name=%s, age=%d %s", "huhx", 25, 1.1);
+        System.out.println(string);
+        String message = MessageFormat.format("name={1}, age={0}, {1} {2,number,#.#}", 25, "huhx", 1.1111);
+        System.out.println(message);
+        System.out.println(String.format("%.2f", BigDecimal.valueOf(1.11111)));
+    }
 }

+ 36 - 0
src/test/java/com/izouma/walkchina/repo/TeamMemberRepositoryTest.java

@@ -0,0 +1,36 @@
+package com.izouma.walkchina.repo;
+
+import com.izouma.walkchina.domain.TeamMember;
+import org.apache.commons.lang3.time.FastDateFormat;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.text.ParseException;
+import java.util.Date;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class TeamMemberRepositoryTest {
+    @Autowired
+    private TeamMemberRepository teamMemberRepository;
+
+    @Test
+    public void addTeamMember() throws ParseException {
+        for (long userId = 750; userId < 759; userId++) {
+            Date start = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000L * Math.round(Math.random() * 9));
+            Date end = FastDateFormat.getInstance("yyyy-MM-dd").parse("2099-01-01");
+            TeamMember teamMember = TeamMember.builder()
+                    .userId(userId)
+                    .leader(677L)
+                    .startDate(start)
+                    .endDate(end)
+                    .active(true)
+                    .build();
+            teamMemberRepository.save(teamMember);
+        }
+    }
+
+}

+ 0 - 1
src/test/java/com/izouma/walkchina/repo/WalkDataRepositoryTest.java

@@ -23,7 +23,6 @@ public class WalkDataRepositoryTest {
         calendar.setTime(new Date());
         calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
         WalkData walkData = WalkData.builder()
-                .active(true)
                 .createdAt(new Date())
                 .modifiedAt(calendar.getTime())
                 .build();

+ 28 - 0
src/test/java/com/izouma/walkchina/repo/WxAccessTokenRepositoryTest.java

@@ -0,0 +1,28 @@
+package com.izouma.walkchina.repo;
+
+import com.izouma.walkchina.domain.WxAccessToken;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class WxAccessTokenRepositoryTest {
+    @Autowired
+    private WxAccessTokenRepository wxAccessTokenRepository;
+
+    @Test
+    public void testRedis() {
+        WxAccessToken wxAccessToken = new WxAccessToken();
+        wxAccessToken.setToken("aaaaa");
+        wxAccessToken = wxAccessTokenRepository.save(wxAccessToken);
+
+        System.out.println(wxAccessTokenRepository.findById(wxAccessToken.getId()).toString());
+
+        System.out.println(wxAccessTokenRepository.findAll());
+    }
+}

+ 42 - 0
src/test/java/com/izouma/walkchina/service/JourneyServiceTest.java

@@ -0,0 +1,42 @@
+package com.izouma.walkchina.service;
+
+import com.izouma.walkchina.repo.CityRepository;
+import com.izouma.walkchina.repo.JourneyStageRepository;
+import com.izouma.walkchina.repo.UserJourneyRepository;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class JourneyServiceTest {
+    @Autowired
+    private CityRepository cityRepository;
+    @Autowired
+    private JourneyService journeyService;
+
+    @Test
+    public void hasJourney() {
+    }
+
+    @Test
+    public void newJourney() {
+        journeyService.newJourney(677L,
+                cityRepository.findByName("南京").getId(),
+                cityRepository.findByName("扬州").getId());
+    }
+
+    @Test
+    public void newDestination() {
+        journeyService.newDestination(677L, cityRepository.findByName("镇江").getId());
+    }
+
+
+    @Test
+    public void updateUserJourney() {
+    }
+}

+ 11 - 25
src/test/java/com/izouma/walkchina/service/MapServiceTest.java

@@ -1,11 +1,9 @@
 package com.izouma.walkchina.service;
 
 import com.google.gson.Gson;
+import com.izouma.walkchina.domain.City;
 import com.izouma.walkchina.dto.Location;
 import com.izouma.walkchina.dto.webservice.DirectionResponse;
-import com.izouma.walkchina.domain.City;
-import com.izouma.walkchina.domain.JourneyStage;
-import com.izouma.walkchina.domain.UserJourney;
 import com.izouma.walkchina.repo.CityRepository;
 import com.izouma.walkchina.repo.JourneyStageRepository;
 import com.izouma.walkchina.repo.UserJourneyRepository;
@@ -32,6 +30,14 @@ public class MapServiceTest {
     public void citiesInRegion() {
     }
 
+    @Test
+    public void citiesInRegion1() {
+    }
+
+    @Test
+    public void usersInRegion() {
+    }
+
     @Test
     public void direction() {
 
@@ -40,30 +46,10 @@ public class MapServiceTest {
         DirectionResponse response = mapService.direction(new Location(from.getLatitude(), from.getLongitude()),
                 new Location(to.getLatitude(), to.getLongitude()));
         System.out.println(new Gson().toJson(response));
-
-        UserJourney userJourney = UserJourney.builder()
-                .userId(3L)
-                .originId(from.getId())
-                .destinationId(to.getId())
-                .distance(response.getResult().getRoutes().get(0).getDistance())
-                .polyline(response.getResult().getRoutes().get(0).getPolyline())
-                .build();
-        userJourney = userJourneyRepository.save(userJourney);
-        JourneyStage journeyStage = JourneyStage.builder()
-                .userId(3L)
-                .journeyId(userJourney.getId())
-                .originId(from.getId())
-                .destinationId(to.getId())
-                .polyline(response.getResult().getRoutes().get(0).getPolyline())
-                .routeSteps(response.getResult().getRoutes().get(0).getSteps())
-                .distance(response.getResult().getRoutes().get(0).getDistance())
-                .progress(1.0)
-                .build();
-        journeyStage = journeyStageRepository.save(journeyStage);
     }
 
     @Test
-    public void newDestination() {
-        mapService.newDestination(3L, cityRepository.findByName("上海").getId());
+    public void userMap() {
+        mapService.userMap(677L);
     }
 }

+ 42 - 0
src/test/java/com/izouma/walkchina/service/WalkDataServiceTest.java

@@ -0,0 +1,42 @@
+package com.izouma.walkchina.service;
+
+import com.izouma.walkchina.domain.WalkData;
+import com.izouma.walkchina.repo.WalkDataRepository;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Date;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class WalkDataServiceTest {
+    @Autowired
+    private WalkDataRepository walkDataRepository;
+
+    @Autowired
+    private WalkDataService walkDataService;
+
+    @Test
+    public void saveWalkData() {
+        for (Long userId = 750L; userId <= 759; userId++) {
+            long ts = System.currentTimeMillis();
+            for (int i = 0; i < 10; i++) {
+                WalkData walkData = WalkData.builder()
+                        .userId(userId)
+                        .steps(Math.round(Math.random() * 20000 + 3000))
+                        .date(new Date(ts))
+                        .build();
+                walkDataRepository.save(walkData);
+                ts -= 24 * 60 * 60 * 1000;
+            }
+        }
+    }
+
+    @Test
+    public void sumWalkSteps() {
+        System.out.println(walkDataRepository.sumTeamWalkSteps(667L, new Date(1561967454000L), new Date()).orElse(0));
+    }
+}