WeChatペイメント公式アカウント決済について詳しく解説
この記事では主にWeChat決済の公式アカウント支払いについて詳しく説明しますWeChat決済の人気に伴い、ほとんどの製品が独自の公式アカウントやミニプログラムなどを開発しています。製品のマーケティングには決済のサポートが必要です。最近、WeChat の公開アカウントを作成しました。番号による支払いには無数の穴があります。今日はそれを皆さんに共有したいと思います。
まず WeChat 支払い API ドキュメントをご覧ください
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
https:// pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_4
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id =open1419317853&token=&lang =zh_CN
少しわかりにくいですが、最初に WeChat の開発者向けドキュメントを読むことをお勧めします。 。 。 。
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
アプリケーションシナリオ
<br/>
必要なjarパッケージ
<!-- 微信支付需要的jar包 --> <dependency> <groupId>xmlpull</groupId> <artifactId>xmlpull</artifactId> <version>1.1.3.1</version> </dependency> <dependency> <groupId>xpp3</groupId> <artifactId>xpp3</artifactId> <version>1.1.4c</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.7</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>fluent-hc</artifactId> <version>4.3.5</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.3.5</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient-cache</artifactId> <version>4.3.5</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.3.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.3.5</version> </dependency>
パブリックアカウントでの支払いが必要パラメータ<br/>
public class WeixinMatchPayConfigure { /** * 域名 项目域名,根据需求自行配置 */ public static final String ROOTURL = WeixinPayConfigure.ROOTURL; /** * 订单域名 项目域名,根据需求自行配置 */ public static final String ORDER_ROOTURL = WeixinPayConfigure.ORDER_ROOTURL; /** * 赛事 域名 项目域名,根据需求自行配置 */ public static final String MATCHURL = "http://www.baidu.com"; /** * 公共账号id 必填 (18位数↓) */ public static final String APPID = WeixinPayConfigure.APPID; /** * 商户id 商户账号 必填 */ public static final String MCH_ID = "11111111"; /** * 应用秘钥 必填(可在微信商户平台上查找) */ public static final String APP_SECRET = "fd87878fsf87fsf8cvsd8"; /**API秘钥*/ 必填(可在微信商户平台上查找) public static final String API_KEY = "fsdfn23482njdvjw23455555"; /** * 统一下单URL 微信官方提供 */ public static final String PAY_UNIFIED_ORDER_API = "https://api.mch.weixin.qq.com/pay/unifiedorder"; /** * 微信公众号交易类型 (扫码支付类型:NATIVE,公众号支付类型:JSAPI) */ public static final String TRADE_TYPE = "JSAPI"; /** * 获取code的回调地址 你项目要展示的首页路径 */ public static final String REDIRECT_URI = "http://order.uxuexi.com/pay/apply.html"; /**微信H5支付结果通知页*/ public static final String NOTIFY_URL = ROOTURL + "/api/pay/weixin/notify.html"; /** * 不弹出授权页面,直接跳转,只能获取用户openid */ public static final String SCOPE = "snsapi_base"; /** * 弹出授权页面,需要用户确认,可以获取用户的较多信息 */ public static final String USERINFOSCOPE = "snsapi_userinfo"; /** * 获取微信code的url(登录授权) */ public static final String GET_CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect"; /** * 获取用户的OpenId的url(必须先获得code之后调用) */ public static final String GET_OPENID_URL = "https://api.weixin.qq.com/sns/oauth2/access_token"; /** * 微信支付成功之后的回调 */ public static final String NOTIFY_ACTIVITY_URL = WeixinPayConfigure.ORDER_ROOTURL + "/pay/wxnotify.json"; }
WeChatユーザーのopenIdを取得します<br/>
大致步骤:获取用户授权(获取code)------------->根据code获取openID(用户的基本信息)
1、配置授权域
这个则是在公众号登陆平台上面配置的↓
<br/>
2、发起API请求获取用户授权
URL:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
需要拼接三个参数:APPID、REDIRECT_URI、SCOPE,代码如下:
//项目入口,如果这个项目是在公众号中,那么公众号菜单下面配置的就是这个接口的路径↓ @At @Ok("jsp:match.entrance") @NotSso public Object entrance() { String codeUrl = WeiXinApiUrlUtil.getMatchUrl(); return codeUrl; } public static String getMatchUrl() { String url = WeixinMatchPayConfigure.GET_CODE_URL; url = url.replace("APPID", urlEnodeUTF8(WeixinMatchPayConfigure.APPID)); url = url.replace("REDIRECT_URI", WeixinMatchPayConfigure.REDIRECT_URI); url = url.replace("SCOPE", WeixinMatchPayConfigure.USERINFOSCOPE); return url; }
返回前端的是个Url路径,同个这个路径来获取微信用户授权,然后跳转我们自己的首页(REDIRECT_URI) 前端页面 <script type="text/javascript"> $(document).ready(function(){ //其实这个时候跳转的URL它会跟着一连串属性,入下图 ↓ window.location.href='${obj}'; }); </script>
3、微信用户openId是什么?<br/>
在微信用户关注公众号时,会对应的产生一个openId(openId:加密后的用户微信号),一个微信用户对应一个公众号产生的openId是唯一,当然,如果该微信号去关注另一个公众号所产生openID肯定和当前这个不一样的,OpenID 是最对『微信应用』的用户唯一值,同一个『微信开发者账号』下的不同应用中,使用同一个『微信用户』登录,此值会不一样,
废话不说,上代码↓
①、上文表明此接口请求带有参数code,那么需在这里接受code参数
@At @Ok("jsp:match.apply") @NotSso public Object apply(@Param("code") String code) { return matchPayViewService.apply(code); }
②、获取openID放到session中去
public Object apply(String code) { //创建空map Map<String, Object> map = MapUtil.map(); //获取session HttpSession session = Mvcs.getReq().getSession(); //获取session中oppenID String oppendId = ConvertUtil.obj2str(session.getAttribute("oppendId")); //非空校验oppenID if (!Util.isEmpty(oppendId)) { map.put("isWeChat", "yes"); return map; } //校验code是否为空,为空说明不是微信公众号支付 if (Util.isEmpty(code)) { map.put("isWeChat", "no"); return map; } //获取访问用户的token,(工具类1) UserInfoAccessTokenDt accessTokenDt = userInfoAccessTokenDtBaseService.getUserAccessToken(code); //获取微信用户信息,(工具类2) UserInfoDt userInfo = userInfoDtBaseService.getUserInfo(accessTokenDt); ExceptionUtil.checkEmpty(userInfo, "获取微信用户信息失败"); map.put("userInfo", userInfo); int sessionInactive = 30 * 60; //把相关数据放到session中去 session.setMaxInactiveInterval(sessionInactive); session.setAttribute("oppendId", userInfo.getOpenid()); session.setAttribute("userInfo", userInfo); map.put("isWeChat", "yes"); //获取当前用户 map.put("userId", fetchUser.getCurrentUserId()); //-----------------------------------------------------权限校验,可根据自己的项目进行业务操作 map.put("isgxltUser", gXUnicomBusinessService.isPermission(fetchUser.getCurrentUserId())); return map; }
注:上面这些是获取微信用户授权、获取用户的基本信息,公众号支付需要用户的openID,所以。。。。。。
创建预支付Url
1、创建订单
①、此处不解释
@At @Ok("jsp:match.createorder") @NotSso public Object createOrder(@Param("..") final OrderAddForm orderAddForm, final String gradeName) { return matchPayViewService.createOrder(orderAddForm, gradeName); }
②、创建订单
public Map<String, Object> createOrder(OrderAddForm orderAddForm, String gradeName) { ExceptionUtil.checkId(orderAddForm.getMatchId(), "赛事ID不能为空"); Map<String, Object> map = MapUtil.map(); orderAddForm.setCustomPrice(matchBaseService.getPrice(orderAddForm.getMatchId()).getPrice()); OrderMatchEntity order = dbDao.insert(orderAddForm.toEntity()); map.put("order", order); map.put("gradeName", gradeName); //拼接预支付订单 String result = sendReqGetPreOrder(order); //转化为JsApiParam对象,(工具类3) JsApiParam jap = dowithWxReturn(result); map.put("jap", jap); return map; }
③、拼接预支付订单参数
private String sendReqGetPreOrder(OrderMatchEntity order) { ExceptionUtil.checkEmpty(order.getId(), "订单id不能为空"); Map<String, Object> params = MapUtil.map(); params.put("appid", WeixinMatchPayConfigure.APPID); params.put("mch_id", WeixinMatchPayConfigure.MCH_ID); params.put("notify_url", WeixinMatchPayConfigure.NOTIFY_ACTIVITY_URL); params.put("trade_type", WeixinMatchPayConfigure.TRADE_TYPE);//单次订单为jsapi方式 int randomNumLength = 32; params.put("nonce_str", RandomUtil.randomString(randomNumLength)); //获取openID params.put("openid", getWxUserInfoWithEx().getOpenid()); String body = "赛事报名"; params.put("body", body); params.put("out_trade_no", order.getId()); long total_fee = AmountUtils.changeY2F(order.getCustomPrice()); params.put("total_fee", total_fee); params.put("device_info", "WEB"); //加密签名,工具类(微信支付PC端文档中有) String sign = Signature.getSign(params, WeixinMatchPayConfigure.API_KEY); params.put("sign", sign); //HttpRequest 工具类(微信支付PC端文档中有) return HttpRequest.sendPost(WeixinMatchPayConfigure.PAY_UNIFIED_ORDER_API, params); } //获取微信标识 private UserInfoDt getWxUserInfoWithEx() { Object userInfo = Mvcs.getReq().getSession().getAttribute("userInfo"); if (Util.isEmpty(userInfo)) { throw ExceptionUtil.bEx("获取你的微信身份的标识失败请重新退出再次进入"); } //类型转换 return ConvertUtil.cast(userInfo, UserInfoDt.class); }
④、处理调用微信预支付订单的返回值
private JsApiParam dowithWxReturn(String result) { //该类见(工具类3) JsApiParam jsApiParam = new JsApiParam(); Map<String, Object> weixinPrepayInfo = MapUtil.map(); try { //------------------解析XML(工具类:微信支付PC端文档中有) weixinPrepayInfo = XMLParser.getMapFromXML(result); String return_code = (String) weixinPrepayInfo.get("return_code"); if ("SUCCESS".equals(return_code)) { String prepay_id = (String) weixinPrepayInfo.get("prepay_id"); //给jsApiParam对象赋值 jsApiParam.setPrepay_id(prepay_id); jsApiParam.setPackageInfo("prepay_id=" + prepay_id); jsApiParam.setPaySign(getJsApiPaySign(jsApiParam)); return jsApiParam; } else { throw ExceptionUtil.bEx("预支付失败"); } } catch (Exception e) { ExceptionUtil.bEx("调用微信预支付接口出错"); } return jsApiParam; }
⑤、调用jsApiParam对象打回前台后,则需要调用微信内部的提供的js方法getBrandWCPayRequest
function onBridgeReady(){ //微信内部提供的js方法 WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":"${obj.jap.appId}", //公众号名称,由商户传入 "timeStamp":"${obj.jap.timeStamp}", //时间戳,自1970年以来的秒数 "nonceStr":"${obj.jap.nonceStr}", //随机串 "package":"${obj.jap.packageInfo}", "signType":"MD5", //微信签名方式: "paySign":"${obj.jap.paySign}" //微信签名 }, function(res){ // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 if (res.err_msg == "get_brand_wcpay_request:ok") { //跳转到成功页面 window.location.href = "http://lannong.uxuexi.com/register/success.html"; } else if (res.err_msg == "get_brand_wcpay_request:cancel") { WeixinJSBridge.call('closeWindow'); } else { } } ); }
⑥、调用⑤后页面则会弹出微信支付框,如图↓
<br/>
支付成功<br/>
1、支付成功后则调用成功后的回调函数
@At @Filters public void wxnotify() throws Exception { matchPayViewService.weChatPayViewService(); }
2、签名校验
public void weChatPayViewService() throws Exception { HttpServletRequest request = Mvcs.getReq(); HttpServletResponse response = Mvcs.getResp(); //获取微信响应的内容 String responseString = getWeiXinResponseContent(request); PrintWriter out = response.getWriter(); String resp = ""; String signKey = WeixinPayConfigure.API_KEY; //------------------------------签名校验↓,(工具类:微信支付PC端文档中有) boolean verify = Signature.checkIsSignValidFromResponseString(responseString, signKey); if (!verify) { logger.error("签名验证失败"); resp = "签名验证失败"; out.write(resp); out.close(); //签名失败直接返回 return; } //解析xml Map<String, Object> map = XMLParser.getMapFromXML(responseString); String result_code = ConvertUtil.obj2str(map.get("result_code")); if (!"SUCCESS".equalsIgnoreCase(result_code)) { resp = PayCommonUtil.getResponseXML("ERROR", "ERROR"); out.write(resp); out.close(); //支付失败直接返回 return; } //处理订单 resp = handleOrder(map); out.write(resp); out.close(); } //获取微信响应内容 private String getWeiXinResponseContent(HttpServletRequest request) throws IOException, UnsupportedEncodingException { InputStream inStream = request.getInputStream(); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outStream.write(buffer, 0, len); } //获取微信调用我们notify_url的返回信息 String responseString = new String(outStream.toByteArray(), "utf-8"); outStream.close(); inStream.close(); return responseString; }
3、处理订单,此处业务不再讲解,不懂得可以去看PC端微信支付文档
@Aop("txDb") private String handleOrder(Map<String, Object> map) throws Exception { String resp = PayCommonUtil.getResponseXML("SUCCESS", "OK"); String transaction_id = ConvertUtil.obj2str(map.get("transaction_id")); String time_end = ConvertUtil.obj2str(map.get("time_end")); String out_trade_no = (String) map.get("out_trade_no"); if (Util.isEmpty(transaction_id) || Util.isEmpty(time_end) || Util.isEmpty(out_trade_no)) { resp = PayCommonUtil.getResponseXML("ERROR", "参数错误,微信支付订单号、支付完成时间、订单号均不能为空"); return resp; } OrderMatchEntity order = dbDao.fetch(OrderMatchEntity.class, ConvertUtil.obj2long(out_trade_no)); if (Util.isEmpty(order)) { resp = PayCommonUtil.getResponseXML("ERROR", "订单不存在"); return resp; } int orderStatus = order.getStatus(); if (OrderStatusEnum.FINISHED.intKey() == orderStatus) { return resp; } if (OrderStatusEnum.WAITING_PAY.intKey() == orderStatus) { //此处写你所需的业务即可 //更新订单为完成状态 //实际支付金额(分) //添加支付记录 } return resp; }
4、公众号微信支付,支付后微信会返回三种状态,如图↓
<br/>
那么,关于三种状态我们所需跳转的页面则可以在前台用js来实现<br/>
function(res){ // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 if (res.err_msg == "get_brand_wcpay_request:ok") { //跳转到成功页面 window.location.href = "http://lannong.uxuexi.com/register/success.html"; } else if (res.err_msg == "get_brand_wcpay_request:cancel") { WeixinJSBridge.call('closeWindow'); } else { } }
工具类<br/>
1、获取访问用户的token
@IocBean public class UserInfoAccessTokenDtBaseService { /** * 通过code获取用户的openId * * @param code 编号 * * @return 用户的openId */ public UserInfoAccessTokenDt getUserAccessToken(String code) { ExceptionUtil.checkEmpty(code, "用户同意授权,获取的code不能为空"); //获取用户openid的连接 String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + WeixinH5PayConfigure.APPID + "&secret=" + WeixinH5PayConfigure.APP_SECRET + "&code=" + code + "&grant_type=authorization_code"; Response res = Http.get(url); String content = res.getContent(); //----------------------------------从 JSON 字符串中,根据获取某种指定类型的 JSON 对象 UserInfoAccessTokenDt accessTokenDt = JsonUtil.fromJson(content, UserInfoAccessTokenDt.class); return accessTokenDt; } }
2、获取微信用户基本信息
@IocBean public class UserInfoDtBaseService { /** * 获取用户信息 * * @param accessTokenDt 获取用户信息的token * * @return 用户信息对象 */ public UserInfoDt getUserInfo(UserInfoAccessTokenDt accessTokenDt) { ExceptionUtil.checkEmpty(accessTokenDt, "访问用户的accessToken不能为空"); String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessTokenDt.getAccess_token() + "&openid=" + accessTokenDt.getOpenid() + "&lang=zh_CN"; Response res = Http.get(url); String content = res.getContent(); //------------------------------------- 从 JSON 字符串中,根据获取某种指定类型的 JSON 对象。↓ UserInfoDt UserInfo = JsonUtil.fromJson(content, UserInfoDt.class); return UserInfo; } } @Data public class UserInfoAccessTokenDt { //TODO(注释去这个链接下找:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html) private String access_token; private String expires_in; private String refresh_token; private String openid; private String scope; private String unionid; }
3、微信公众号支付参数
@Data public class JsApiParam { /** * 公众号appid */ private String appId = WeixinH5PayConfigure.APPID; /** * 时间戳 */ private String timeStamp = System.currentTimeMillis() + ""; /** * 随机字符串 */ private String nonceStr = RandomUtil.randIntString(32); /** * 签名方式 */ private String signType = "MD5"; /** * 预支付id */ private String packageInfo; /** * 支付签名 */ private String paySign; /** * 订单号 */ private String orderNo; /** * 微信预付单号 */ private String prepay_id; }
以上がWeChatペイメント公式アカウント決済について詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック

Baidu Map APP は現在、多くのユーザーに好まれる旅行ナビゲーション ソフトウェアとなっているため、ここにある機能の一部は包括的であり、毎日の旅行で遭遇する可能性のある問題のいくつかを解決するために無料で選択して操作できます。自分だけの旅行ルートを設定して、自分だけの旅行プランを立てましょう。該当するルートを確認した上で、公共交通機関を利用しても、自転車、徒歩、タクシーなど、目的に応じて適切な移動方法を選択することができます。あなたのニーズに対応したナビゲーションルートがあり、特定の場所にうまく導くことができます。そうすれば、誰もがタクシーを利用することを選択した場合、より便利だと感じるでしょう。多くのドライバーがいます。彼らは皆、オンラインで注文を受け付け、タクシー配車は可能です。超になる

C++ のモード関数の詳細な説明 統計において、モードとは、一連のデータ内で最も頻繁に現れる値を指します。 C++ 言語では、モード関数を記述することによって、任意のデータセット内のモードを見つけることができます。モード関数はさまざまな方法で実装できます。一般的に使用される 2 つの方法を以下で詳しく紹介します。 1 つ目の方法は、ハッシュ テーブルを使用して各数値の出現回数をカウントすることです。まず、各数値をキー、出現回数を値とするハッシュ テーブルを定義する必要があります。次に、特定のデータセットに対して次を実行します。

Windows オペレーティング システムは世界で最も人気のあるオペレーティング システムの 1 つであり、その新バージョン Win11 が大きな注目を集めています。 Win11 システムでは、管理者権限の取得は重要な操作であり、管理者権限を取得すると、ユーザーはシステム上でより多くの操作や設定を実行できるようになります。この記事では、Win11システムで管理者権限を取得する方法と、権限を効果的に管理する方法を詳しく紹介します。 Win11 システムでは、管理者権限はローカル管理者とドメイン管理者の 2 種類に分かれています。ローカル管理者はローカル コンピュータに対する完全な管理権限を持っています

uniapp は、小さなプログラム、アプリ、および H5 を同時に開発できるクロスプラットフォームのアプリケーション開発フレームワークです。 uniapp アプリケーションでは、支払いと注文の管理が非常に一般的なニーズです。この記事では、uniappアプリケーションに決済機能や注文管理を実装する方法と具体的なコード例を紹介します。 1. 決済機能の実装 決済機能はオンライン取引を実現するための鍵であり、通常、サードパーティの決済プラットフォームの SDK を統合する必要があります。 uniapp に支払い機能を実装するための具体的な手順は次のとおりです。 サードパーティの支払いプラットフォームを登録して取得します。

OracleSQL の除算演算の詳細な説明 OracleSQL では、除算演算は一般的かつ重要な数学演算であり、2 つの数値を除算した結果を計算するために使用されます。除算はデータベース問合せでよく使用されるため、OracleSQL での除算演算とその使用法を理解することは、データベース開発者にとって重要なスキルの 1 つです。この記事では、OracleSQL の除算演算に関する関連知識を詳細に説明し、読者の参考となる具体的なコード例を示します。 1. OracleSQL での除算演算

C++ の剰余関数の詳しい説明 C++ では、剰余演算子 (%) を使用して、2 つの数値を除算した余りを計算します。これは、オペランドが任意の整数型 (char、short、int、long など) または浮動小数点数型 (float、double など) になる二項演算子です。剰余演算子は、被除数と同じ符号の結果を返します。たとえば、整数の剰余演算の場合、次のコードを使用して実装できます。

PHP のモジュロ演算子 (%) は、2 つの数値を除算した余りを取得するために使用されます。この記事では、モジュロ演算子の役割と使用法について詳しく説明し、読者の理解を深めるために具体的なコード例を示します。 1. モジュロ演算子の役割 数学では、整数を別の整数で割ると、商と余りが得られます。たとえば、10 を 3 で割ると、商は 3 になり、余りは 1 になります。モジュロ演算子は、この剰余を取得するために使用されます。 2. モジュロ演算子の使用法 PHP では、% 記号を使用してモジュロを表します。

Linux システム コール system() 関数の詳細説明 システム コールは、Linux オペレーティング システムの非常に重要な部分であり、システム カーネルと対話する方法を提供します。その中でも、system()関数はよく使われるシステムコール関数の一つです。この記事では、system() 関数の使用法を詳しく紹介し、対応するコード例を示します。システム コールの基本概念 システム コールは、ユーザー プログラムがオペレーティング システム カーネルと対話する方法です。ユーザープログラムはシステムコール関数を呼び出してオペレーティングシステムを要求します。
