[Spring cloud step by step implementation of the ad system] 6. Service Configuration & Test achieve & Zuul

DAO layer design implementation

Here we use Spring DATA JPAto implement database operations, of course, we can use Mybatisall the same, we are still in a user table operation as an example:

/**
 * AdUserRepository for 用户数据库操作接口
 * 继承自JpaRepository<AdUser, Long>,第一个参数AdUser代表当前要操作的实体类的class定义,第二个参数Long表示该类的主键类型
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang</a>
 */

public interface AdUserRepository extends JpaRepository<AdUser, Long> { 
    /**
     * 根据用户名称获取用户
     *
     * @param username 名称
     * @return 用户对象
     */
    AdUser findByUserName(String username);

    List<AdUser> findAllByUserName(String userName);
}
  • The default JPARepository implementation method, if we just inherited JpaRepositorywithout the achievement of specific methods of operation, we can also do it by using the default method CRUDof operation, as follows:

    UTOOLS1564192818939.png

Service implementation functions

Create a service package, the user is still operating, for example, create com.sxzhongf.ad.service.IUserServiceand com.sxzhongf.ad.service.impl.UserServiceImpl, UserServiceImplwe realized IUserService.

  1. Creating IUserServiceinterfaces
/**
 * IUserService for 用户service
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang | 若初</a>
 */
public interface IUserService {
    /**
     * 创建用户接口
     *
     * @param userRequestVO {@link UserRequestVO}
     * @return {@link UserResponseVO}
     * @throws AdException 错误
     */
    UserResponseVO createUser(UserRequestVO userRequestVO) throws AdException;

    List<AdUser> findAllByUserName(String userName);
}
  1. Use IUserServiceInterface
/**
 * UserServiceImpl for 用户service
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang | 若初</a>
 */
@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    private final AdUserRepository userRepository;

    @Autowired
    public UserServiceImpl(AdUserRepository userRepository) {
        this.userRepository = userRepository;
    }

    /**
     * 创建用户
     *
     * @param userRequestVO {@link UserRequestVO}
     * @return result {@link UserResponseVO}
     */
    @Override
    @Transactional
    public UserResponseVO createUser(UserRequestVO userRequestVO) throws AdException {
        if (!userRequestVO.validate()) {
            log.error("Request params error: {}", userRequestVO);
            throw new AdException(Constants.ErrorMessage.REQUEST_PARAM_ERROR);
        }
        //查重
        AdUser existUser = userRepository.findByUserName(userRequestVO.getUserName());
        if (existUser != null) {
            log.error("{} user is not exist.", userRequestVO.getUserName());
            throw new AdException(Constants.ErrorMessage.USER_EXIST);
        }
        AdUser user = userRepository.save(new AdUser(userRequestVO.getUserName(), CommonUtils.md5(userRequestVO.getUserName())));
        log.info("current user is : {}", user);
        return new UserResponseVO(user.getUserId(), user.getUserName(), user.getToken(),
                user.getCreateTime(), user.getUpdateTime());
    }

    @Override
    public List<AdUser> findAllByUserName(String userName) {
        return userRepository.findAllByUserName(userName);
    }
}
  1. Creating a Data Transfer Object (dto / vo)

    In fact, a lot of people here will be particularly depressed, do not know what difference these names, personal recommendation is that we do not tangle, dto (data transfer object), that represents the object of our passing in each layer, presentation layer objects vo in operation. But this is just a name, it's essentially a object, you pass to the DAO layer can it? Sure, you pass a separate field are possible. So, no need too tangled this information quibble sometimes it will be counterproductive.

/**
 * UserRequestVO for 创建用户请求对象VO
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang | 若初</a>
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRequestVO {
    private String userName;
    public boolean validate() {
        return !StringUtils.isEmpty(userName);
    }
}

---

/**
 * UserResponseVO for 用户响应VO
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang | 若初</a>
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserResponseVO {
    private Long userId;
    private String userName;
    private String token;
    private Date createTime;
    private Date updateTime;
}
  1. Because the error message may be the same, then we extract a constant class to encapsulate.
/**
 * Constants for TODO
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang | 若初</a>
 */
public class Constants {
    /**
     * 通用错误信息异常类
     */
    public static class ErrorMessage {
        public static final String REQUEST_PARAM_ERROR = "请求参数异常";
        public static final String USER_EXIST = "用户已存在";
        public static final String USER_NOT_EXIST = "用户不存在";
    }
}
  1. Create a utility class in Common Project below com.sxzhongf.ad.common.utils.CommonUtils, used to be md5 encrypted user username to obtain the token information.
/**
 * CommonUtils for 工具类
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang | 若初</a>
 */
@Slf4j
public class CommonUtils {
    /**
     * md5 加密
     */
    public static String md5(String value) {
        return DigestUtils.md5Hex(value).toUpperCase();
    }
}

Reference to create an implementation of the user, in order to achieve other table operations.

Controller implementation

Still to implement user functions, for example:

/**
 * UserController for 用户controller
 *
 * @author <a href="mailto:[email protected]">Isaac.Zhang | 若初</a>
 */
@RestController
@Slf4j
@RequestMapping("/user")
public class UserController {
    @Autowired
    private IUserService userService;

    @PostMapping(path = "/create")
    public UserResponseVO createUser(@RequestBody UserRequestVO requestVO) throws AdException {
        log.info("ad-sponsor: createUser -> {}", JSON.toJSONString(requestVO));
        return userService.createUser(requestVO);
    }

    @GetMapping(path = "/get")
    public CommonResponse getUserList(@Param(value = "username") String username) throws AdException {
        log.info("ad-sponsor: getUserList -> {}", JSON.toJSONString(username));
        return new CommonResponse(userService.findAllByUserName(username));
    }
}
Configuration advertising system in the gateway

We put the system in the configuration, the configuration of server.servlet.context-path:/ad-sponsorsuch a path, the current system means that all requests need the path with the ad-sponsor, for example: http://xxx/ad-sponsor/user/get?username=yyyIt is necessary to request the gateway. According to the above, we configure our current delivery system in the Gateway service:

spring:
  application:
    name: ad-gateway-zuul
server:
  port: 1111
eureka:
  client:
    service-url:
      defaultZone: http://server1:7777/eureka/,http://server2:8888/eureka/,http://server3:9999/eureka/
  instance:
    hostname: ad-gateway-zuul
##############################################
# 以下为重要信息
zuul:
  ignored-services: '*' # 过滤所有请求,除了下面routes中声明过的服务
  # 配置网关路由规则
  routes:
    sponsor: #在路由中自定义服务路由名称
      path: /ad-sponsor/**
      serviceId: mscx-ad-sponsor #微服务name
      strip-prefix: false
    search: #在路由中自定义服务路由名称
      path: /ad-search/**
      serviceId: mscx-ad-search #微服务name
      strip-prefix: false
  prefix: /gateway/api
  strip-prefix: false #不对 prefix: /gateway/api 设置的路径进行截取,默认转发会截取掉配置的前缀
Test
  • Direct access to the delivery system

    Call curl -G http://localhost:7000/ad-sponsor/user/get?username=Isaac%20Zhang, return the result:

{
  code: 0,  // 统一成功标示
  message: "success", // 统一处理结果message
  data: [  // 具体的对象信息
    {
      userId: 10,
      userName: "Isaac Zhang",
      token: "2D3ABB6F2434109A105170FB21D00453",
      userStatus: 1,
      createTime: 1561118873000,
      updateTime: 1561118873000
    }
  ]
}
  • By calling gateway

    Because I added the prefix in the gateway configuration prefix: /gateway/api, therefore, we need to add the time of the visit on the prefix information, otherwise it will report a 404 error.

    curl -G http://localhost:1111/gateway/api/ad-sponsor/user/get?username=Isaac%20ZhangWe found that the results do not show it as we imagine.

    bogon:~ zhangpan$ http://localhost:1111/gateway/api/ad-sponsor/user/get?username=Isaac%20Zhang
    -bash: http://localhost:1111/gateway/api/ad-sponsor/user/get?username=Isaac%20Zhang: No such file or directory

    why? We take a look at the log:

    2019-07-27 20:44:19.093  INFO 4766 --- [nio-1111-exec-4] c.s.a.g.filter.ValidateTokenFilter       : GET request to http://localhost:1111/gateway/api/ad-sponsor/user/get
    2019-07-27 20:44:19.093  WARN 4766 --- [nio-1111-exec-4] c.s.a.g.filter.ValidateTokenFilter       : access token is empty
    2019-07-27 20:44:19.098  INFO 4766 --- [nio-1111-exec-4] c.s.ad.gateway.filter.AccessLogFilter    : Request "/gateway/api/ad-sponsor/user/get" spent : 0 seconds.
    2019-07-27 20:48:37.801  INFO 4766 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration

    We can clearly see ValidateTokenFilter : access token is emptywhy there is such an error it? That is because when I configure the gateway, add an interception:

    /**
    * ValidateTokenFilter for 服务token校验
    *
    * @author <a href="mailto:[email protected]">Isaac.Zhang</a>
    */
    @Slf4j
    @Component
    public class ValidateTokenFilter extends ZuulFilter {
    ...
      @Override
      public Object run() throws ZuulException {
          RequestContext ctx = RequestContext.getCurrentContext();
          HttpServletRequest request = ctx.getRequest();
          log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
    
          Object accessToken = request.getHeader("accessToken"); //.getParameter("accessToken");
          if (accessToken == null) {
              log.warn("access token is empty");
              ctx.setSendZuulResponse(false);
              ctx.setResponseStatusCode(401);
    //            ctx.setResponseBody(body)对返回body内容进行编辑
              return null;
          }
          log.info("access token ok");
          return null;
      }
    }

    Observe the code we found from'll RequestHeaderget the accessTokenparameters, we have not provided, of course, it would be incorrect report. Next, we try to provide the parameters:

    bogon:~ zhangpan$ curl -H "accessToken:true" http://localhost:1111/gateway/api/ad-sponsor/user/get?username=Isaac%20Zhang
    ---返回
    {"code":0,"message":"success","data":[{"userId":10,"userName":"Isaac Zhang","token":"2D3ABB6F2434109A105170FB21D00453","userStatus":1,"createTime":1561118873000,"updateTime":1561118873000}]}

    At this point, our ad delivery system has a simple function to achieve full completion, and can be forwarded through the gateway.

Guess you like

Origin blog.51cto.com/1917331/2424663