バックエンドはサービスを提供し、通常はJSON文字列を返しますが、一部のシナリオでは、画像編集インターフェイスなどのバイナリストリームを直接返す必要がある場合があります。現時点で何ができますか?
主な用途はhttpservletResponseオブジェクトで、ケースは次のように実装されています
@RequestMapping(value = {"/img/render"}、method = {requestmethod.get、requestmethod.post、requestmethod.options})@crossorigin(ryssing = "*")@responsebublic string execute(httpservletrequest、httpservletrequte、httpservletletletreconse) IMGは、画像バイトのバイナリストリーム[] img = xxxです。 httpservletResponse.setContentType( "Image/PNG"); outputStream os = httpservletResponse.getOutputStream(); os.write(img); os.flush(); os.close(); 「成功」を返します;}注意すべきこと
一般的に言えば、バックエンドによって提供されるサービスインターフェイスは、しばしばJSONデータを返します。前述のように、写真を直接返すシーンで、写真を返す一般的な方法は何ですか?
では、コントローラーは、上記の3つの使用姿勢を同時にサポートする方法をどのように提供する必要がありますか?
返す方法はいくつかあるため、どのようなものを選択するかは、もちろんフロントエンドで指定されているため、パラメーターを要求するBeanオブジェクトを定義できます。
@DataPublic Class BasereQuest {private static final long serialversionuid = 1146303518394712013l; / ** *出力画像方法: * * url:httpアドレス(デフォルトメソッド) * base64:base64エンコード *ストリーム:直接戻り画像 * */ private string outtype; /***画像タイプを返します* jpg | png | webp | gif */ private string mediatype; public returnTypeenum returnType(){return returnTypeenum.getEnum(outtype); } public mediatypeenum mediatype(){return mediatypeenum.getenum(mediatype); }}判断を簡素化するために、2つの注釈が定義されました。1つのReturnTypeenumともう1つのMediatypeenumです。もちろん、必要性は特に大きくありません。以下は両方の定義です。
public enum returnTypeenum {url( "url")、stream( "stream")、base64( "base");プライベート文字列タイプ。 returnTypeenum(string type){this.type = type; } private static map <string、returntypeenum> map; static {map = new Hashmap <>(3); for(returntypeenum e:returnTypeenum.values()){map.put(e.type、e); }} public static returntypeenum getEnum(string type){if(type == null){return url; } returnTypeenum e = map.get(type.tolowercase()); e == nullを返しますか? URL:e; }} @datapublic enum mediatypeenum {imagejpg( "jpg"、 "image/jpeg"、 "ffd8ff")、imagegif( "gif"、 "image/gif"、 "47494638")、imagepng( "png"、 "" emage/png "、" 89504e47 ")、") 「Image/Webp」、「52494646」)、プライベートファイナルストリングext;プライベートファイナルストリングマイム;プライベートファイナルストリングマジック; mediatypeenum(string ext、string mime、string magic){this.ext = ext; this.mime = mime; this.magic = magic; } private static map <string、mediatypeenum> map; static {map = new Hashmap <>(4); for(mediatypeenum e:values()){map.put(e.getext()、e); }} public static mediatypeenum getEnum(string type){if(type == null){return imagejpg; } mediatypeenum e = map.get(type.tolowercase()); e == nullを返しますか? ImageJPG:e; }}上記は、リクエストパラメーターでカプセル化されたBeanです。もちろん、返す対応する豆もあります。
@datapublic class Baseresponse { / ***画像の相対パスを返します* / private string path; / ***画像のhttps形式を返します*/ private string url; / *** base64形式の画像*/プライベート文字列ベース;}説明:
実際のプロジェクト環境では、リクエストパラメーターとリターンは上記ほど単純ではないため、上記の豆を継承するか、対応する形式を自分で定義することで実装できます。
目標は明確であるため、パッケージングはこれの最も明確なステップです
保護されたvoid buildResponse(Baserequest request、baseresponse response、byte [] bytes)throws selferror {switch(request.returntype()){case url:upload(bytes、response);壊す;ケースBase64:base64(バイト、応答);壊す;ケースストリーム:ストリーム(バイト、リクエスト); }} private void upload(byte [] bytes、baseresponse response)throws selferror {try {//画像サーバーにアップロードし、文字列パス= uploadutil.upload(bytes); if(stringutils.isblank(path)){// failed throw new internalerror(null); } Response.SetPath(PATH); Response.seturl(cdnutil.img(path)); } catch(ioException e){// cdn exception log.error( "cdn error!e:{}"、e);新しいcdnuploaderror(e.getmessage()); }} // base64private void base64(byte [] bytes、baseeresponse response){string base = base64.getEncoder()。encodetostring(bytes); Response.setBase(base);} //バイナリ画像プライベートボイドストリーム(byte [] bytes、baserequest request)を返すselferror {try {mediatypeenum mediatype = request.mediatype(); httpservletResponse servletResponse =((servletRequestattributes)requestContExtholder.getRequestattributes())。getResponse(); servletResponse.setContentType(mediatype.getMime()); outputStream os = servletResponse.getOutputStream(); os.write(バイト); os.flush(); os.close(); } catch(Exception e){log.Error( "一般的なリターンストリームIMGエラー!req:{}、e:{}"、request、e); if(stringutils.isnotblank(e.getmessage())){show new internalerror(e.getMessage()); } else {throw new internalerror(null); }}}説明:
上記のカスタム例外方法は無視してください。それらを使用する必要がある場合、これらのカスタム例外を完全に排除できます。ここでは、主に次の利点のために、このカスタム例外方法が実際のプロジェクトで使用される理由について簡単に説明します
Global Exception Capture(ControllerAdvie)と併せて、非常に便利で使いやすいです
すべての例外は、情報統計とアラームを容易にするために中央に処理されます
たとえば、統一された場所で例外カウントを実行してから特定のしきい値を超えた後、担当者に電話して、例外ケースが発生する各場所に積極的に埋める必要はありません。
エラーステータスコードのレイヤーごとの送信は避けてください
- これは主にWebサービス用です。一般に、返されたJSON文字列に対応するエラーステータスコードとエラーメッセージが含まれます。
- 例外ケースがどこにでも表示される場合があります。この例外情報を維持するために、データがレイヤーごとにコントローラーレイヤーに渡されます。または、threadlocalにあります。明らかに、これらの方法はどちらも使用するのに便利ではありません
もちろん、欠点があります。
例外方法、追加のパフォーマンスオーバーヘッド、そのため、カスタムの例外では、次の方法をカバーしました。完全なスタックはありません
@OverridePublic同期スロー可能なfillinStacktrace(){これを返します;}一部の人々は、この習慣をコーディングする方法を好まないかもしれません
練習していないと言っても面白くないようです。上記のデザインは、私が維持しているオープンソースプロジェクトのクイックメディアに完全に反映されています。もちろん、上記とはいくつかの違いがあります。結局のところ、それはビジネスにより関連しています。興味がある場合は、参照できます。
QuickMedia:https://github.com/liuyueyi/quick-media:
BaseAction:com.hust.hui.quickmedia.web.wxapi.wxbaseaction#buildreturn
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。