瀏覽代碼

0605 购买车票逻辑梳理

Qing 1 年之前
父節點
當前提交
eaf2d3797e

+ 49 - 0
12306-demo/my-gateway/pom.xml

@@ -32,6 +32,55 @@
             <artifactId>spring-cloud-starter-loadbalancer</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.32</version>
+        </dependency>
+
+        <!-- jjwt start -->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+            <version>2.3.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-impl</artifactId>
+            <version>2.3.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-core</artifactId>
+            <version>2.3.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.activation</groupId>
+            <artifactId>activation</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+        <!-- jjwt end -->
+
+<!--        <dependency>-->
+<!--            <groupId>org.opengoofy.index12306</groupId>-->
+<!--            <artifactId>index12306-base-spring-boot-starter</artifactId>-->
+<!--            <version>${project.version}</version>-->
+<!--        </dependency>-->
+
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2</artifactId>
+            <version>2.0.50.android8</version>
+        </dependency>
 
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 35 - 0
12306-demo/my-gateway/src/main/java/com/sf/mygateway/config/Config.java

@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sf.mygateway.config;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 过滤器配置
+ * 公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
+ */
+@Data
+public class Config {
+
+    /**
+     * 黑名单前置路径
+     */
+    private List<String> blackPathPre;
+}

+ 47 - 0
12306-demo/my-gateway/src/main/java/com/sf/mygateway/config/UserConstant.java

@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sf.mygateway.config;
+
+/**
+ * 用户常量
+ * 公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
+ */
+public final class UserConstant {
+
+    /**
+     * 用户 ID Key
+     */
+    public static final String USER_ID_KEY = "userId";
+
+    /**
+     * 用户名 Key
+     */
+    public static final String USER_NAME_KEY = "username";
+
+    /**
+     * 用户真实名称 Key
+     */
+    public static final String REAL_NAME_KEY = "realName";
+
+    /**
+     * 用户 Token Key
+     */
+    public static final String USER_TOKEN_KEY = "token";
+
+    public static final String AUTHORIZATION_KEY = "Authorization";
+}

+ 92 - 0
12306-demo/my-gateway/src/main/java/com/sf/mygateway/filter/TokenValidateGatewayFilterFactory.java

@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sf.mygateway.filter;
+
+import com.alibaba.nacos.client.naming.utils.CollectionUtils;
+import com.sf.mygateway.config.Config;
+import com.sf.mygateway.config.UserConstant;
+import com.sf.mygateway.toolkit.JWTUtil;
+import com.sf.mygateway.toolkit.UserInfoDTO;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * SpringCloud Gateway Token 拦截器
+ * 公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
+ */
+@Component
+public class TokenValidateGatewayFilterFactory extends AbstractGatewayFilterFactory<Config> {
+
+    public TokenValidateGatewayFilterFactory() {
+        super(Config.class);
+    }
+
+    /**
+     * 注销用户时需要传递 Token
+     */
+    public static final String DELETION_PATH = "/api/user-service/deletion";
+
+    @Override
+    public GatewayFilter apply(Config config) {
+        return (exchange, chain) -> {
+            ServerHttpRequest request = exchange.getRequest();
+            String requestPath = request.getPath().toString();
+            if (isPathInBlackPreList(requestPath, config.getBlackPathPre())) {
+                String token = request.getHeaders().getFirst("Authorization");
+                // TODO 需要验证 Token 是否有效,有可能用户注销了账户,但是 Token 有效期还未过
+                UserInfoDTO userInfo = JWTUtil.parseJwtToken(token);
+                if (!validateToken(userInfo)) {
+                    ServerHttpResponse response = exchange.getResponse();
+                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
+                    return response.setComplete();
+                }
+
+                ServerHttpRequest.Builder builder = exchange.getRequest().mutate().headers(httpHeaders -> {
+                    httpHeaders.set(UserConstant.USER_ID_KEY, userInfo.getUserId());
+                    httpHeaders.set(UserConstant.USER_NAME_KEY, userInfo.getUsername());
+                    httpHeaders.set(UserConstant.REAL_NAME_KEY, URLEncoder.encode(userInfo.getRealName(), StandardCharsets.UTF_8));
+                    if (Objects.equals(requestPath, DELETION_PATH)) {
+                        httpHeaders.set(UserConstant.USER_TOKEN_KEY, token);
+                    }
+                });
+                return chain.filter(exchange.mutate().request(builder.build()).build());
+            }
+            return chain.filter(exchange);
+        };
+    }
+
+    private boolean isPathInBlackPreList(String requestPath, List<String> blackPathPre) {
+        if (CollectionUtils.isEmpty(blackPathPre)) {
+            return false;
+        }
+        return blackPathPre.stream().anyMatch(requestPath::startsWith);
+    }
+
+    private boolean validateToken(UserInfoDTO userInfo) {
+        return userInfo != null;
+    }
+}

+ 91 - 0
12306-demo/my-gateway/src/main/java/com/sf/mygateway/toolkit/JWTUtil.java

@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sf.mygateway.toolkit;
+
+import com.alibaba.fastjson2.JSON;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.sf.mygateway.config.UserConstant.*;
+
+
+/**
+ * JWT 工具类
+ * 公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
+ */
+@Slf4j
+public final class JWTUtil {
+
+    private static final long EXPIRATION = 86400L;
+    public static final String TOKEN_PREFIX = "Bearer ";
+    public static final String ISS = "index12306";
+    public static final String SECRET = "SecretKey039245678901232039487623456783092349288901402967890140939827";
+
+    /**
+     * 生成用户 Token
+     *
+     * @param userInfo 用户信息
+     * @return 用户访问 Token
+     */
+    public static String generateAccessToken(UserInfoDTO userInfo) {
+        Map<String, Object> customerUserMap = new HashMap<>();
+        customerUserMap.put(USER_ID_KEY, userInfo.getUserId());
+        customerUserMap.put(USER_NAME_KEY, userInfo.getUsername());
+        customerUserMap.put(REAL_NAME_KEY, userInfo.getRealName());
+        String jwtToken = Jwts.builder()
+                .signWith(SignatureAlgorithm.HS512, SECRET)
+                .setIssuedAt(new Date())
+                .setIssuer(ISS)
+                .setSubject(JSON.toJSONString(customerUserMap))
+                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION * 1000))
+                .compact();
+        return TOKEN_PREFIX + jwtToken;
+    }
+
+    /**
+     * 解析用户 Token
+     *
+     * @param jwtToken 用户访问 Token
+     * @return 用户信息
+     */
+    public static UserInfoDTO parseJwtToken(String jwtToken) {
+        if (StringUtils.hasText(jwtToken)) {
+            String actualJwtToken = jwtToken.replace(TOKEN_PREFIX, "");
+            try {
+                Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(actualJwtToken).getBody();
+                Date expiration = claims.getExpiration();
+                if (expiration.after(new Date())) {
+                    String subject = claims.getSubject();
+                    return JSON.parseObject(subject, UserInfoDTO.class);
+                }
+            } catch (ExpiredJwtException ignored) {
+            } catch (Exception ex) {
+                log.error("JWT Token解析失败,请检查", ex);
+            }
+        }
+        return null;
+    }
+}

+ 49 - 0
12306-demo/my-gateway/src/main/java/com/sf/mygateway/toolkit/UserInfoDTO.java

@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sf.mygateway.toolkit;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 用户信息实体
+ * 公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class UserInfoDTO {
+
+    /**
+     * 用户 ID
+     */
+    private String userId;
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 真实姓名
+     */
+    private String realName;
+}

+ 14 - 0
12306-demo/my-gateway/src/main/resources/application.yml

@@ -16,7 +16,21 @@ spring:
           uri: lb://my-user-service/api/user-service/**
           predicates:
             - Path=/api/user-service/**
+          filters:
+            - name: TokenValidate
+              args:
+                blackPathPre:
+                  - /api/user-service/passenger
         - id: my-ticket-service
           uri: lb://my-ticket-service/api/ticket-service/**
           predicates:
             - Path=/api/ticket-service/**
+          filters:
+            - name: TokenValidate
+              args:
+                blackPathPre:
+                  - /api/ticket-service/ticket/purchase
+        - id: my-order-service
+          uri: lb://my-order-service/api/order-service/**
+          predicates:
+            - Path=/api/order-service/**

+ 6 - 4
12306-demo/my-ticket-service/src/main/java/com/sf/service/handler/TrainSeatTypeSelector.java

@@ -122,18 +122,20 @@ public final class TrainSeatTypeSelector {
 
         Result<List<PassengerRespDTO>> passengerRemoteResult;
         List<PassengerRespDTO> passengerRemoteResultList;
+        // 远程调用 调用user微服务获取乘车人信息
+        String username = UserContext.getUsername();
         try {
-            // 远程调用 调用user微服务获取乘车人信息
-            passengerRemoteResult = userRemoteService.listPassengerQueryByIds(UserContext.getUsername(), passengerIds);
+            passengerRemoteResult = userRemoteService.listPassengerQueryByIds(
+                    username, passengerIds);
             if (!passengerRemoteResult.isSuccess()
                     || CollUtil.isEmpty(passengerRemoteResultList = passengerRemoteResult.getData())) {
                 throw new RemoteException("用户服务远程调用查询乘车人相信信息错误");
             }
         } catch (Throwable ex) {
             if (ex instanceof RemoteException) {
-                log.error("用户服务远程调用查询乘车人相信信息错误,当前用户:{},请求参数:{}", UserContext.getUsername(), passengerIds);
+                log.error("用户服务远程调用查询乘车人相信信息错误,当前用户:{},请求参数:{}", username, passengerIds);
             } else {
-                log.error("用户服务远程调用查询乘车人相信信息错误,当前用户:{},请求参数:{}", UserContext.getUsername(), passengerIds, ex);
+                log.error("用户服务远程调用查询乘车人相信信息错误,当前用户:{},请求参数:{}", username, passengerIds, ex);
             }
             throw ex;
         }

+ 7 - 3
12306-demo/my-ticket-service/src/main/java/com/sf/service/impl/TicketServiceImpl.java

@@ -312,6 +312,10 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, TicketDO> imple
     }
 
     public TicketPurchaseRespDTO executePurchaseTickets(PurchaseTicketReqDTO requestParam) {
+//        String username = "admin";
+//        String userId = "1683025552364568576";
+        String username = UserContext.getUsername();
+        String userId = UserContext.getUserId();
         List<TicketOrderDetailRespDTO> ticketOrderDetailResults = new ArrayList<>();
         String trainId = requestParam.getTrainId();
         // 节假日高并发购票Redis能扛得住么?详情查看:https://nageoffer.com/12306/question
@@ -319,7 +323,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, TicketDO> imple
         List<TrainPurchaseTicketRespDTO> trainPurchaseTicketResults = trainSeatTypeSelector.select(trainDO.getTrainType(), requestParam);
         List<TicketDO> ticketDOList = trainPurchaseTicketResults.stream()
                 .map(each -> TicketDO.builder()
-                        .username(UserContext.getUsername())
+                        .username(username)
                         .trainId(Long.parseLong(requestParam.getTrainId()))
                         .carriageNumber(each.getCarriageNumber())
                         .seatNumber(each.getSeatNumber())
@@ -370,8 +374,8 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, TicketDO> imple
                     .departureTime(trainStationRelationDO.getDepartureTime())
                     .arrivalTime(trainStationRelationDO.getArrivalTime())
                     .ridingDate(trainStationRelationDO.getDepartureTime())
-                    .userId(UserContext.getUserId())
-                    .username(UserContext.getUsername())
+                    .userId(userId)
+                    .username(username)
                     .trainId(Long.parseLong(requestParam.getTrainId()))
                     .ticketOrderItems(orderItemCreateRemoteReqDTOList)
                     .build();

+ 2 - 2
12306-demo/my-user-service/src/main/java/com/sf/controller/PassengerController.java

@@ -21,8 +21,8 @@ public class PassengerController {
 
     @GetMapping("/api/user-service/passenger/query")
     public Result<List<PassengerRespDTO>> listPassengerQueryByUsername() {
-        String username = "admin";
-        // UserContext.getUsername()
+//        String username = "admin";
+        String username = UserContext.getUsername();
         return Results.success(passengerService.listPassengerQueryByUsername(username));
     }
 

+ 11 - 0
12306-demo/my-user-service/src/main/java/com/sf/controller/UserController.java

@@ -1,9 +1,15 @@
 package com.sf.controller;
 
+import com.sf.dto.req.UserLoginReqDTO;
+import com.sf.dto.resp.UserLoginRespDTO;
 import com.sf.entity.UserDO;
 import com.sf.service.IUserService;
+import org.opengoofy.index12306.framework.starter.convention.result.Result;
+import org.opengoofy.index12306.framework.starter.web.Results;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
@@ -19,4 +25,9 @@ public class UserController {
         userService.save(user);
         return "success";
     }
+
+    @PostMapping("/api/user-service/v1/login")
+    public Result<UserLoginRespDTO> login(@RequestBody UserLoginReqDTO requestParam) {
+        return Results.success(userService.login(requestParam));
+    }
 }

+ 42 - 0
12306-demo/my-user-service/src/main/java/com/sf/dto/req/UserLoginReqDTO.java

@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sf.dto.req;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 用户登录请求参数
+ * 公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserLoginReqDTO {
+
+    /**
+     * 用户名
+     */
+    private String usernameOrMailOrPhone;
+
+    /**
+     * 密码
+     */
+    private String password;
+}

+ 52 - 0
12306-demo/my-user-service/src/main/java/com/sf/dto/resp/UserLoginRespDTO.java

@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sf.dto.resp;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 用户登录返回参数
+ * 公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserLoginRespDTO {
+
+    /**
+     * 用户 ID
+     */
+    private String userId;
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 真实姓名
+     */
+    private String realName;
+
+    /**
+     * Token
+     */
+    private String accessToken;
+}

+ 4 - 0
12306-demo/my-user-service/src/main/java/com/sf/service/IUserService.java

@@ -1,7 +1,11 @@
 package com.sf.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.sf.dto.req.UserLoginReqDTO;
+import com.sf.dto.resp.UserLoginRespDTO;
 import com.sf.entity.UserDO;
 
 public interface IUserService extends IService<UserDO> {
+    UserLoginRespDTO login(UserLoginReqDTO requestParam);
+
 }

+ 43 - 0
12306-demo/my-user-service/src/main/java/com/sf/service/impl/UserServiceImpl.java

@@ -1,11 +1,54 @@
 package com.sf.service.impl;
 
+import com.alibaba.fastjson2.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sf.dto.req.UserLoginReqDTO;
+import com.sf.dto.resp.UserLoginRespDTO;
 import com.sf.entity.UserDO;
 import com.sf.mapper.UserMapper;
 import com.sf.service.IUserService;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import org.opengoofy.index12306.framework.starter.cache.DistributedCache;
+import org.opengoofy.index12306.framework.starter.convention.exception.ClientException;
+import org.opengoofy.index12306.framework.starter.convention.exception.ServiceException;
+import org.opengoofy.index12306.frameworks.starter.user.core.UserInfoDTO;
+import org.opengoofy.index12306.frameworks.starter.user.toolkit.JWTUtil;
 import org.springframework.stereotype.Service;
 
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
 @Service
+@RequiredArgsConstructor
 public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements IUserService {
+
+    private final UserMapper userMapper;
+    private final DistributedCache distributedCache;
+
+    @Override
+    public UserLoginRespDTO login(UserLoginReqDTO requestParam) {
+
+        String username = requestParam.getUsernameOrMailOrPhone();
+        username = Optional.ofNullable(username).orElse(requestParam.getUsernameOrMailOrPhone());
+        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
+                .eq(UserDO::getUsername, username)
+                .eq(UserDO::getPassword, requestParam.getPassword())
+                .select(UserDO::getId, UserDO::getUsername, UserDO::getRealName);
+        UserDO userDO = userMapper.selectOne(queryWrapper);
+        if (userDO != null) {
+            UserInfoDTO userInfo = UserInfoDTO.builder()
+                    .userId(String.valueOf(userDO.getId()))
+                    .username(userDO.getUsername())
+                    .realName(userDO.getRealName())
+                    .build();
+            String accessToken = JWTUtil.generateAccessToken(userInfo);
+            UserLoginRespDTO actual = new UserLoginRespDTO(userInfo.getUserId(), requestParam.getUsernameOrMailOrPhone(), userDO.getRealName(), accessToken);
+            distributedCache.put(accessToken, JSON.toJSONString(actual), 30, TimeUnit.MINUTES);
+            return actual;
+        }
+        throw new ServiceException("账号不存在或密码错误");
+    }
 }

+ 6 - 6
12306-demo/pom.xml

@@ -24,7 +24,7 @@
     <properties>
         <java.version>17</java.version>
         <spring.cloud.version>2022.0.3</spring.cloud.version>
-        <spring-cloud-starter-bootstrap.version>4.1.0</spring-cloud-starter-bootstrap.version>
+<!--        <spring-cloud-starter-bootstrap.version>4.1.0</spring-cloud-starter-bootstrap.version>-->
         <spring.cloud.alibaba.version>2022.0.0.0-RC2</spring.cloud.alibaba.version>
     </properties>
 
@@ -46,11 +46,11 @@
                 <scope>import</scope>
             </dependency>
 
-            <dependency>
-                <groupId>org.springframework.cloud</groupId>
-                <artifactId>spring-cloud-starter-bootstrap</artifactId>
-                <version>${spring-cloud-starter-bootstrap.version}</version>
-            </dependency>
+<!--            <dependency>-->
+<!--                <groupId>org.springframework.cloud</groupId>-->
+<!--                <artifactId>spring-cloud-starter-bootstrap</artifactId>-->
+<!--                <version>${spring-cloud-starter-bootstrap.version}</version>-->
+<!--            </dependency>-->
         </dependencies>
     </dependencyManagement>