构建自己的steam游戏史低查询平台

原文地址

原文链接

前言

总在别人的网站查询Steam游戏史低总觉得有点没意思,我们来做一个自己的Steam游戏辅助平台吧。这里我已经实现部分,有需要的小伙伴可以直接跳转参考,Steam游戏史低查询

首先,这里我们不讨论前端页面展示,前端页面按照个人喜好设计就可以。其次,我们这里不使用爬虫抓取数据,毕竟我们不是专门做数据平台的,没有必要浪费服务资源去进行大批量的数据抓取

实现

API

那么我们需要先拿到Steam平台的Api

  • 官网公开接口,Developer Community Steam Web API以及Steamworks Web API
  • 如果你觉得官网对于Api的解释不够详细,比如枚举,那么你可以参考网友总结的,steamwebapi
  • 当你认为官网的Api不能满足你的需求的时候,你可以参考SteamApis所提供的接口支持,这是收费的,你总不能叫给人白给你打工吧
  • 如果你和站长一样,是个穷逼的话,可以参考IsThereAnyDeal所提供的游戏平台数据查询接口支持,免费的,暂时
  • 当然,最后一个不知道从哪冒出来,但是大伙都知道的Steam游戏详情接口http://store.steampowered.com/api/appdetails?appids=,类似接口可以参考StorefrontAPI,这些接口不稳定可能随时会无法调通
  • 如果你有更好的或者更多的Steam接口提供网站,欢迎分享在评论区

调用

和之前一样,我们技术栈是Java17+Spring3+Cloud4的架构,所以我们这里使用的是Spring Cloud OpenFeignopenfeign没啥好说的,但是这里着重提一下,如果你调用的是官网接口,那么其实没有特殊处理下你是无法直接获得相关数据的,我们需要使用中间服务器转发。关于转发服务器构建,请参考本站的构建自己的中间服务器以及构建自己的中间服务器(续篇),这里简单说下openfeign的中间服务器配置,如何使用自己的中间服务器转发请求

openfeign的中间服务器配置

我们可以从openfeign的源码FeignAutoConfiguration中了解到,openfeign可以使用的clientOkHttpClientApacheHttp5Client以及HttpClient

我们这里就直接使用默认的Client写入代理

@Configuration
public class FeignConfiguration {

    @Value("${nezuko.proxy.host}")
    private String proxyHost;

    @Value("${nezuko.proxy.port}")
    private Integer proxyPort;

    @Bean
    public Client feignClient() {
        return new Client.Proxied(null, null,
                new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)));
    }
}

当然,你也可以使用其他的客户端,比如okHttp,当然需要在配置文件中将spring.cloud.openfeign.okhttp.enabled设置为true

@Configuration
public class FeignConfiguration {

    @Value("${nezuko.proxy.host}")
    private String proxyHost;

    @Value("${nezuko.proxy.port}")
    private Integer proxyPort;

    @Bean
    public OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)))
                .build();
    }
}

所以我们无论使用自己的代理服务还是其他方式,都只需要一个地址和一个端口即可。地址好办,如果没有使用容器那么地址就是localhost,如果使用了容器那么地址就是宿主机地址,所以我们主要拿到端口就可以了

端口获取

此处相关内容参考原文,csdn相关规定不允许发

举例

比如我们我们这里实现一个,查询游戏列表,然后展示详情和史低的功能,我们的实现如下

控制层

@RestController
@RequestMapping("/steam")
public class StreamController {
    @Autowired
    public StreamController(ISteamService steamService) {
        this.steamService = steamService;
    }

    private final ISteamService steamService;

    @GetMapping("/game/{steamId}/detail")
    public ResultObj<SteamGameDetailVo> getGameDetail(@PathVariable String steamId) {
        return ResultObj.success(ConversionUtils.convertObj(
                steamService.getGameDetail(steamId), SteamGameDetailVo.class));
    }

    @GetMapping("/game/search")
    public ResultObj<List<SteamGameSimpleVo>> searchGame(@RequestParam String name) {
        return ResultObj.success(ConversionUtils.convertList(
                steamService.getGameList(name), SteamGameSimpleVo.class));
    }
}

实现层

@Service
@Slf4j
public class SteamServiceImpl implements ISteamService {
    
    @Resource
    private SteamStoreApiService steamStoreApiService;

    @Resource
    private AnyDealApiService anyDealApiService;

    @Override
    public SteamGameDetailBo getGameDetail(String steamId) {
        //param
        SteamStoreAppDetailParam param = new SteamStoreAppDetailParam();
        param.setAppIdList(Collections.singletonList(steamId));
        //call
        Map<String, SteamStoreAppDetailVo> steamIdDetailMap = steamStoreApiService.getAppDetail(param);
        //check
        if (CollectionUtils.isEmpty(steamIdDetailMap) ||
                ObjectUtils.isEmpty(steamIdDetailMap.get(steamId)) ||
                !steamIdDetailMap.get(steamId).getSuccess()) {
            //todo
            throw new RuntimeException();
        }
        //return
        return ConversionUtils.convertObj(steamIdDetailMap.get(steamId).getData(), SteamGameDetailBo.class);
    }

    @Override
    public List<SteamGameSimpleBo> getGameList(String name) {
        //param
        AnyDealSearchGameParam param = new AnyDealSearchGameParam();
        param.setName(name);
        //call
        AnyDealSearchVo anyDealSearchVo = anyDealApiService.searchGame(param);
        //check
        if (ObjectUtils.isEmpty(anyDealSearchVo) ||
                ObjectUtils.isEmpty(anyDealSearchVo.getData()) ||
                ObjectUtils.isEmpty(anyDealSearchVo.getData().getDealGameSimpleBoList())) {
            return new ArrayList<>();
        }
        //render
        List<SteamGameSimpleBo> results = ConversionUtils.convertList(
                anyDealSearchVo.getData().getDealGameSimpleBoList(), SteamGameSimpleBo.class);
        List<String> dealPlainList = results.stream().map(SteamGameSimpleBo::getDealPlain).toList();
        AnyDealGetOverviewVo gameInfo =
                anyDealApiService.getGameOverview(new AnyDealGetOverviewParam(dealPlainList));
        if (!ObjectUtils.isEmpty(gameInfo) && !ObjectUtils.isEmpty(gameInfo.getData())) {
            for (SteamGameSimpleBo simpleBo : results) {
                overviewRender(gameInfo, simpleBo);
            }
        }
        results.removeIf(result -> null == result.getSteamId());
        //return
        return results;
    }

    private void overviewRender(AnyDealGetOverviewVo gameInfo, SteamGameSimpleBo simpleBo) {
        try {
            AnyDealGameOverviewBo overviewBo = gameInfo.getData().get(simpleBo.getDealPlain());
            Matcher matcher = Pattern.compile("/[0-9]+/").matcher(overviewBo.getPrice().getUrl());
            String steamId = null;
            while (matcher.find()) {
                steamId = matcher.group();
            }
            assert steamId != null;
            steamId = steamId.replace("/", "");
            simpleBo.setSteamId(Long.valueOf(steamId));
            simpleBo.setImageUrl(String.format(SteamConstant.GUESS_STEAM_IMAGE, steamId));
            simpleBo.setCurPrice(overviewBo.getPrice().getPrice());
            simpleBo.setLowestPrice(overviewBo.getLowest().getPrice());
        } catch (NullPointerException ignore) {
        }
    }

}

openfeign调用接口

@FeignClient(name = "steam-store-api", url = "${nezuko.steam.api.steam-store}")
public interface SteamStoreApiService {

    @GetMapping("/api/appdetails")
    Map<String, SteamStoreAppDetailVo> getAppDetail(@SpringQueryMap SteamStoreAppDetailParam param);

}
@FeignClient(name = "any-deal-api", url = "${nezuko.steam.api.any-deal}")
public interface AnyDealApiService {

    @GetMapping("/v02/search/search")
    AnyDealSearchVo searchGame(@SpringQueryMap AnyDealSearchGameParam param);

    @GetMapping("/v01/game/overview")
    AnyDealGetOverviewVo getGameOverview(@SpringQueryMap AnyDealGetOverviewParam param);

}

参数对象

@Data
public class SteamStoreAppDetailParam {

    @Param("appids")
    private List<String> appIdList;

    /**
     * <a href="https://partner.steamgames.com/doc/store/localization/languages">steam language</a>
     */
    @Param("l")
    private String language = SteamConstant.DEFAULT_LANG_CODE;

    @Param("cc")
    private String countryCode;

    @Param("filters")
    private List<String> fileterList;

}
@Data
public class AnyDealSearchGameParam {

    private String key = SpringNezukoConfiguration.StaticConfig.anyDealKey;

    @Param("q")
    private String name;

    private Integer limit = 20;

    @Param("strict")
    private Integer isStrict = 0;

}
@Data
@NoArgsConstructor
public class AnyDealGetOverviewParam {

    private String key = SpringNezukoConfiguration.StaticConfig.anyDealKey;

    private String region = SteamConstant.DEFAULT_REGION;

    private String country = SteamConstant.DEFAULT_COUNTRY;

    private String shop = SteamConstant.DEFAULT_SHOPS;

    private String allowed = SteamConstant.DEFAULT_SHOPS;

    private String plains;

    /**
     * 该接口不支持List<String>的url写法,只支持逗号分隔的写法
     */
    public AnyDealGetOverviewParam(List<String> dealPlainList) {
        plains = String.join(",", dealPlainList);
    }
}

至此我们就可以通过查询列出列表

然后点击列表查看详情了

最后

关于最后的例子只是一个简单实现,没有使用很多字段,小伙伴们可以在看下API后写出一个内容丰富的,带有自己色彩的页面

原文地址

原文链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值